home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / pgp20src.zip / KEYMGMT.C < prev    next >
C/C++ Source or Header  |  1992-09-03  |  68KB  |  2,220 lines

  1. /*    keymgmt.c  - Key management routines for PGP.
  2.     PGP: Pretty Good(tm) Privacy - public key cryptography for the masses.
  3.  
  4.     (c) Copyright 1990-1992 by Philip Zimmermann.  All rights reserved.
  5.     The author assumes no liability for damages resulting from the use
  6.     of this software, even if the damage results from defects in this
  7.     software.  No warranty is expressed or implied.
  8.  
  9.     All the source code Philip Zimmermann wrote for PGP is available for
  10.     free under the "Copyleft" General Public License from the Free
  11.     Software Foundation.  A copy of that license agreement is included in
  12.     the source release package of PGP.  Code developed by others for PGP
  13.     is also freely available.  Other code that has been incorporated into
  14.     PGP from other sources was either originally published in the public
  15.     domain or was used with permission from the various authors.  See the
  16.     PGP User's Guide for more complete information about licensing,
  17.     patent restrictions on certain algorithms, trademarks, copyrights,
  18.     and export controls.  
  19. */
  20.  
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #ifdef UNIX
  24. #include <sys/types.h>
  25. #endif
  26. #include <time.h>
  27. #include <ctype.h>
  28. #include "mpilib.h"
  29. #include "idea.h"
  30. #include "random.h"
  31. #include "crypto.h"
  32. #include "fileio.h"
  33. #include "keymgmt.h"
  34. #include "genprime.h"
  35. #include "rsagen.h"
  36. #include "mpiio.h"
  37. #include "language.h"
  38. #include "pgp.h"
  39.  
  40.  
  41. /*
  42. **    Convert to or from external byte order.
  43. **    Note that convert_byteorder does nothing if the external byteorder
  44. **  is the same as the internal byteorder.
  45. */
  46. #define convert2(x,lx)    convert_byteorder( (byteptr)&(x), (lx) )
  47. #define convert(x)        convert2( (x), sizeof(x) )
  48.  
  49.  
  50. /*
  51.  * check if userid matches the substring, magic characters ^ and $
  52.  * can be used to match start and end of userid.
  53.  * the comparison is case insensitive
  54.  */
  55. boolean userid_match(char *userid, char *substr)
  56. {
  57.     boolean match_end = FALSE;
  58.     int id_len, sub_len, i;
  59.     char buf[256], sub[256], *p;
  60.  
  61.     if (substr == NULL || *substr == '\0')
  62.         return(TRUE);
  63.     if (userid == NULL || *userid == '\0')
  64.         return(FALSE);
  65.  
  66.     id_len = strlen(userid);
  67.     for (i = 0; i <= id_len; ++i)
  68.         buf[i] = tolower(userid[i]);
  69.  
  70.     sub_len = strlen(substr);
  71.     for (i = 0; i <= sub_len; ++i)
  72.         sub[i] = tolower(substr[i]);
  73.  
  74. #ifdef MAGIC_MATCH
  75.     if (sub_len > 1 && sub[sub_len - 1] == '$')
  76.     {
  77.         match_end = TRUE;
  78.         sub[--sub_len] = '\0';
  79.     }
  80.     if (*sub == '^')
  81.     {    if (match_end)
  82.             return(!strcmp(buf, sub + 1));
  83.         else
  84.             return(!strncmp(buf, sub + 1, sub_len - 1));
  85.     }
  86. #endif
  87.     if (sub_len > id_len)
  88.         return(FALSE);
  89.  
  90.     if (match_end)
  91.         return(!strcmp(buf + id_len - sub_len, sub));
  92.  
  93.     p = buf;
  94.     while ((p = strchr(p, *sub)) != NULL)
  95.     {
  96.         if (strncmp(p, sub, sub_len) == 0)
  97.             return(TRUE);
  98.         ++p;
  99.     }
  100.     return(FALSE);
  101. }
  102.  
  103. int
  104. is_key_ctb (byte ctb)
  105. {
  106.     return(ctb == CTB_CERT_PUBKEY  ||  ctb == CTB_CERT_SECKEY);
  107. }
  108.  
  109.  
  110. char *keyIDstring(byte *keyID)
  111. /*    Return printable key fragment, which is an abbreviation of 
  112.     the public key.
  113.     Show LEAST significant 64 bits (KEYFRAGSIZE bytes) of modulus,
  114.     LSB last.  Yes, that's LSB LAST.
  115. */
  116. {    short i,j;
  117.     static char keyIDbuf[2*KEYFRAGSIZE+1];
  118.     char *bufptr;    /* ptr to Key ID string */
  119.     bufptr = keyIDbuf;
  120.     fill0(bufptr,sizeof(keyIDbuf));
  121. #ifdef XLOWFIRST    /* LSB-first keyID format */
  122.     j = KEYFRAGSIZE;
  123.     for (i=KEYFRAGSIZE-1; i>=0; i--)    /* print LSB last */
  124.     {    if (--j < 3)    /* only show bottom 3 bytes of keyID */
  125.         {    sprintf(bufptr,"%02X",keyID[i]);
  126.             bufptr += 2;
  127.         }
  128.         *bufptr = 0;
  129.     }
  130. #else        /* MSB-first keyID format */
  131.     j = KEYFRAGSIZE;
  132.     for (i=0; i<KEYFRAGSIZE; i++)    /* print LSB last */
  133.     {    if (--j < 3)    /* only show bottom 3 bytes of keyID */
  134.         {    sprintf(bufptr,"%02X",keyID[i]);
  135.             bufptr += 2;
  136.         }
  137.         *bufptr = 0;
  138.     }
  139. #endif
  140.     return(keyIDbuf);
  141. }    /* keyIDstring */
  142.  
  143.  
  144.  
  145. void extract_keyID(byteptr keyID, unitptr n)
  146. /*    Extract key fragment from modulus n.  keyID byte array must be
  147.     at least KEYFRAGSIZE bytes long.
  148. */
  149. {    byte buf[MAX_BYTE_PRECISION+2];
  150.     short i, j;
  151.  
  152.     fill0(buf,KEYFRAGSIZE+2); /* in case n is too short */
  153.     reg2mpi(buf,n);    /* MUST be at least KEYFRAGSIZE long */
  154. #ifdef XLOWFIRST
  155.     i = reg2mpi(buf,n);    /* MUST be at least KEYFRAGSIZE long */
  156.     /* For LSB-first keyID format, start of keyID is: */
  157.     i = 2;    /* skip over the 2 bytes of bitcount */
  158.     for (j=0; j<KEYFRAGSIZE; )
  159.         keyID[j++] = buf[i++];
  160. #else
  161.     i = reg2mpi(buf,n);    /* MUST be at least KEYFRAGSIZE long */
  162.     /* For MSB-first keyID format, start of keyID is: */
  163.     i = i + 2 - KEYFRAGSIZE;
  164.     for (j=0; j<KEYFRAGSIZE; )
  165.         keyID[j++] = buf[i++];
  166. #endif
  167.  
  168. }    /* extract_keyID */
  169.  
  170.  
  171.  
  172. char *key2IDstring(unitptr n)
  173. /*    Derive the key abbreviation fragment from the modulus n, 
  174.     and return printable string of key ID.
  175.     n is key modulus from which to extract keyID.
  176. */
  177. {    byte keyID[KEYFRAGSIZE];
  178.     extract_keyID(keyID, n);
  179.     return (keyIDstring(keyID));
  180. }    /* key2IDstring */
  181.  
  182.  
  183.  
  184. void showkeyID(byteptr keyID)
  185. /*    Print key fragment, which is an abbreviation of the public key. */
  186. {
  187.     fprintf(pgpout,"%s",keyIDstring(keyID));
  188. }    /* showkeyID */
  189.  
  190.  
  191.  
  192. void writekeyID(unitptr n, FILE *f)
  193. /*    Write message prefix keyID to a file.
  194.     n is key modulus from which to extract keyID.
  195. */
  196. {    byte keyID[KEYFRAGSIZE];
  197.     extract_keyID(keyID, n);
  198.     fwrite(keyID,1,KEYFRAGSIZE,f);
  199. }    /* writekeyID */
  200.  
  201.  
  202.  
  203. boolean checkkeyID(byte *keyID, unitptr n)
  204. /*    Compare specified keyID with one derived from actual key modulus n. */
  205. {
  206.     byte keyID0[KEYFRAGSIZE];
  207.     if (keyID==NULL) /* no key ID -- assume a good match */
  208.         return (TRUE);
  209.     extract_keyID(keyID0, n);
  210.     return(equal_buffers(keyID,keyID0,KEYFRAGSIZE));
  211. }    /* checkkeyID */
  212.  
  213.  
  214.  
  215. /* external function prototype, from mpiio.c */
  216. void dump_unit_array(string s, unitptr r);
  217.  
  218. void write_trust (FILE *f, byte trustbyte)
  219. /*    Write a key control packet to f, with the specified trustbyte data.
  220.  */
  221. {
  222.     byte ctb;
  223.     byte keyctrllen;
  224.  
  225.     ctb = CTB_KEYCTRL;
  226.     fwrite(&ctb,1,1,f);        /* write key control header byte */
  227.     keyctrllen = 1;
  228.     fwrite(&keyctrllen,1,1,f);    /* write key control length */
  229.     fwrite(&trustbyte,1,1,f);    /* write key control */
  230. }
  231.  
  232. short writekeyfile(char *fname, boolean hidekey, byte *timestamp, byte *userid, 
  233.     unitptr n, unitptr e, unitptr d, unitptr p, unitptr q, unitptr u)
  234. /*    Write key components p, q, n, e, d, and u to specified file.
  235.     hidekey is TRUE iff key should be encrypted.
  236.     userid is a length-prefixed Pascal-type character string. 
  237.     We write three packets: a key packet, a key control packet, and
  238.     a userid packet.  We assume the key being written is our own,
  239.     so we set the control bits for full trust.
  240. */
  241. {    FILE *f;
  242.     byte ctb;
  243.     byte alg, version;
  244.     word16 validity;
  245.     word16 cert_length;
  246.     extern word16 mpi_checksum;
  247.     byte iv[8];
  248.     int i;
  249.  
  250.     /* open file f for write, in binary (not text) mode...*/
  251.     if ((f = fopen(fname,"wb")) == NULL)
  252.     {    fprintf(pgpout,PSTR("\n\007Unable to create key file '%s'.\n"), fname);
  253.         return(-1);
  254.     }
  255.     /*** Begin key certificate header fields ***/
  256.     if (d==NULL)
  257.     {    /* public key certificate */
  258.         ctb = CTB_CERT_PUBKEY;
  259.         cert_length = 1 + SIZEOF_TIMESTAMP + 2 + 1 + (countbytes(n)+2)
  260.             + (countbytes(e)+2);
  261.     }    /* public key certificate */
  262.     else
  263.     {    /* secret key certificate */
  264.         ctb = CTB_CERT_SECKEY;
  265.             cert_length = 1 + SIZEOF_TIMESTAMP + 2 + 1
  266.             + (countbytes(n)+2)
  267.             + (countbytes(e)+2)
  268.             + 1 + (hidekey ? 8 : 0)        /* IDEA algorithm byte and IV */
  269.             + (countbytes(d)+2)
  270.             + (countbytes(p)+2)    + (countbytes(q)+2) 
  271.             + (countbytes(u)+2) + 2;
  272.  
  273.     }    /* secret key certificate */
  274.  
  275.     fwrite(&ctb,1,1,f);        /* write key certificate header byte */
  276.     convert(cert_length);    /* convert to external byteorder */
  277.     fwrite(&cert_length,1,sizeof(cert_length),f);
  278.     version = VERSION_BYTE;
  279.     fwrite(&version,1,1,f);        /* set version number */
  280.     convert_byteorder(timestamp,4);    /* convert to external form */
  281.     fwrite(timestamp,1,4,f); /* write certificate timestamp */
  282.     convert_byteorder(timestamp,4);    /* convert back to internal form */
  283.     validity = 0;
  284.     fwrite (&validity,1,sizeof(validity),f);    /* validity period */
  285.     alg = RSA_ALGORITHM_BYTE;
  286.     fwrite(&alg,1,1,f);
  287.     write_mpi(n,f,FALSE);
  288.     write_mpi(e,f,FALSE);
  289.  
  290.     if (is_secret_key(ctb))    /* secret key */
  291.     {
  292.         /* Write byte for following algorithm */
  293.         alg = (hidekey)?IDEA_ALGORITHM_BYTE:0;
  294.         fwrite(&alg,1,1,f);
  295.  
  296.         if (hidekey)  /* store encrypted IV */
  297.         {    for (i=0; i<8; i++)
  298.                 iv[i] = randombyte();
  299.             if (hidekey)  /* encrypt the IV */
  300.                 ideacfb(iv,8);
  301.             fwrite(iv,1,8,f);    /* write out the IV */
  302.         }
  303.         mpi_checksum = 0;
  304.         write_mpi(d,f,hidekey);
  305.         write_mpi(p,f,hidekey);
  306.         write_mpi(q,f,hidekey);
  307.         write_mpi(u,f,hidekey);
  308.         /* Write checksum here - based on plaintext values */
  309.         convert(mpi_checksum);
  310.         fwrite (&mpi_checksum,1,sizeof(mpi_checksum),f);
  311.     } else {
  312.         /* Keyring control packet, public keys only */
  313.         write_trust (f, KC_OWNERTRUST_ULTIMATE | KC_BUCKSTOP);
  314.     }
  315.     /* User ID packet */
  316.     ctb = CTB_USERID;
  317.     fwrite(&ctb,1,1,f);        /* write userid header byte */
  318.     fwrite(userid,1,userid[0]+1,f);    /* write user ID */
  319.     if (d == NULL)    /* only on public keyring */
  320.         write_trust (f, KC_LEGIT_COMPLETE);
  321.     fclose(f);
  322. #ifdef DEBUG
  323.     fprintf(pgpout,"\n%d-bit %s key written to file '%s'.\n",
  324.         countbits(n),
  325.         is_secret_key(ctb) ? "secret" : "public" ,
  326.         fname);
  327. #endif
  328.     return(0);
  329. }    /* writekeyfile */
  330.  
  331.  
  332.  
  333. /* Return -1 on EOF, else read next key packet, return its ctb, and
  334.  * advance pointer to beyond the packet.
  335.  * This is short of a "short form" of readkeypacket
  336.  */
  337. short nextkeypacket(FILE *f, byte *pctb)
  338. {
  339.     word32 cert_length;
  340.     int count;
  341.     byte ctb;
  342.  
  343.     *pctb = 0;    /* assume no ctb for caller at first */
  344.     count = fread(&ctb,1,1,f);    /* read key certificate CTB byte */
  345.     if (count==0) return(-1);    /* premature eof */
  346.     *pctb = ctb;    /* returns type to caller */
  347.     if ((ctb != CTB_CERT_PUBKEY) && (ctb != CTB_CERT_SECKEY)  &&
  348.             (ctb != CTB_USERID)  &&  (ctb != CTB_KEYCTRL)  &&
  349.             !is_ctb_type(ctb,CTB_SKE_TYPE) &&
  350.             !is_ctb_type(ctb,CTB_COMMENT_TYPE))
  351.         /* Either bad key packet or X/Ymodem padding detected */
  352.         return ((ctb == 0x1A) ? -1 : -2);
  353.  
  354.     cert_length = getpastlength(ctb, f); /* read certificate length */
  355.  
  356.     if (cert_length > MAX_KEYCERT_LENGTH-3)
  357.         return(-3);    /* bad length */
  358.  
  359.     fseek(f, cert_length, SEEK_CUR);
  360.     return(0);
  361. } /* nextkeypacket */
  362.  
  363.  
  364. short readkeypacket(FILE *f, boolean hidekey, byte *pctb,
  365.     byte *timestamp, char *userid,
  366.     unitptr n ,unitptr e, unitptr d, unitptr p, unitptr q, unitptr u,
  367.     byte *sigkeyID, byte *keyctrl)
  368. /*    Reads a key certificate from the current file position of file f.
  369.     Depending on the certificate type, it will set the proper fields
  370.     of the return arguments.  Other fields will not be set.
  371.     pctb is always set.
  372.     If the packet is CTB_CERT_PUBKEY or CTB_CERT_SECKEY, it will
  373.     return timestamp, n, e, and if the secret key components are
  374.     present and d is not NULL, it will read, decrypt if hidekey is
  375.     true, and return d, p, q, and u.
  376.     If the packet is CTB_KEYCTRL, it will return keyctrl as that byte.
  377.     If the packet is CTB_USERID, it will return userid.
  378.     If the packet is CTB_COMMENT_TYPE, it won't return anything extra.
  379.     The file pointer is left positioned after the certificate.
  380. */
  381. {
  382.     byte ctb;
  383.     word16 cert_length;
  384.     int count;
  385.     byte version, alg, mdlen;
  386.     word16 validity;
  387.     word16 chksum;
  388.     extern word16 mpi_checksum;
  389.     byte iv[8];
  390.  
  391.     /*** Begin certificate header fields ***/
  392.     *pctb = 0;    /* assume no ctb for caller at first */
  393.     count = fread(&ctb,1,1,f);    /* read key certificate CTB byte */
  394.     if (count==0) return(-1);    /* premature eof */
  395.     *pctb = ctb;    /* returns type to caller */
  396.     if ((ctb != CTB_CERT_PUBKEY) && (ctb != CTB_CERT_SECKEY)  &&
  397.             (ctb != CTB_USERID)  &&  (ctb != CTB_KEYCTRL)  &&
  398.             !is_ctb_type(ctb,CTB_SKE_TYPE) &&
  399.             !is_ctb_type(ctb,CTB_COMMENT_TYPE))
  400.         /* Either bad key packet or X/Ymodem padding detected */
  401.         return ((ctb == 0x1A) ? -1 : -2);
  402.  
  403.     cert_length = getpastlength(ctb, f); /* read certificate length */
  404.  
  405.     if (cert_length > MAX_KEYCERT_LENGTH-3)
  406.         return(-3);    /* bad length */
  407.  
  408.     if (ctb == CTB_USERID)
  409.     {    if (cert_length > 255)
  410.             return(-3);            /* Bad length error */
  411.         if (userid)
  412.         {    userid[0] = cert_length;        /* Save user ID length */
  413.             fread(userid+1,1,cert_length,f); /* read rest of user ID */
  414.         } else
  415.             fseek (f, (long)cert_length, SEEK_CUR);
  416.         return(0);    /* normal return */
  417.     }
  418.     else if (is_ctb_type (ctb, CTB_COMMENT_TYPE))
  419.     {       fseek(f, (long)cert_length, SEEK_CUR);        /* Just skip packet */
  420.         return(0);    /* normal return */
  421.     }
  422.     else if (is_ctb_type (ctb, CTB_SKE_TYPE))
  423.     {    long fpos = ftell(f);        /* Remember where we are now */
  424.         if (sigkeyID)
  425.         {    fread(&version,1,1,f);        /* Read version of sig packet */
  426.             if (version_error(version, VERSION_BYTE))
  427.                 return(-6);            /* Need a later version */
  428.             /* Skip timestamp, validity period, and type byte */
  429.             fread(&mdlen, 1, 1, f);
  430.             fseek(f, (long) mdlen, SEEK_CUR);
  431.             /* Read and return KEY ID */
  432.             fread(sigkeyID,1,KEYFRAGSIZE,f);
  433.         }
  434.         fseek(f,fpos+cert_length,SEEK_SET);    /* Skip to end of cert */
  435.         return(0);    /* normal return */
  436.     }
  437.     else if (ctb == CTB_KEYCTRL)
  438.     {    if (cert_length != 1)
  439.             return(-3);            /* Bad length error */
  440.         if (keyctrl)
  441.             fread(keyctrl,1,cert_length,f);    /* Read key control byte */
  442.         else
  443.             fseek (f, (long)cert_length, SEEK_CUR);
  444.         return(0);    /* normal return */
  445.     }
  446.     /* Here we have a key packet */
  447.     if (n != NULL)
  448.         set_precision(MAX_UNIT_PRECISION);    /* safest opening assumption */
  449.     fread(&version,1,1,f);    /* read and check version */
  450.     if (version_error(version, VERSION_BYTE))
  451.         return(-6);            /* Need a later version */
  452.     if (timestamp)
  453.     {    fread(timestamp,1,SIZEOF_TIMESTAMP,f);    /* read certificate timestamp */
  454.         convert_byteorder(timestamp,SIZEOF_TIMESTAMP); /* convert from external form */
  455.     } else
  456.         fseek(f, (long)SIZEOF_TIMESTAMP, SEEK_CUR);
  457.     fread(&validity,1,sizeof(validity),f);    /* Read validity period */
  458.     convert(validity);    /* convert from external byteorder */
  459.     /* We don't use validity period yet */
  460.     fread (&alg, 1, 1, f);
  461.     if (version_error(alg, RSA_ALGORITHM_BYTE))
  462.         return(-6);            /* Need a later version */
  463.     /*** End certificate header fields ***/
  464.  
  465.     /* We're past certificate headers, now look at some key material...*/
  466.  
  467.     cert_length -= 1 + SIZEOF_TIMESTAMP + 2 + 1;
  468.  
  469.     if (n==NULL)    /* Skip key certificate data */
  470.     {       fseek(f, (long)cert_length, SEEK_CUR);
  471.         return(0);
  472.     }
  473.  
  474.     if (read_mpi(n,f,TRUE,FALSE) < 0)
  475.         return(-4);    /* data corrupted, return error */
  476.  
  477.     /* Note that precision was adjusted for n */
  478.  
  479.     if (read_mpi(e,f,FALSE,FALSE) < 0)
  480.         return(-4);    /* data corrupted, error return */
  481.  
  482.     cert_length -= (countbytes(n)+2) + (countbytes(e)+2);
  483.  
  484.     if (d==NULL)    /* skip rest of this key certificate */
  485.     {       fseek(f, (long)cert_length, SEEK_CUR);
  486.         return(0);            /* Normal return */
  487.     }
  488.     if (is_secret_key(ctb))
  489.     {    byte    alg = 0;
  490.         fread (&alg,1,1,f);
  491.         if (alg && version_error(alg,IDEA_ALGORITHM_BYTE))
  492.             return(-6);            /* Unknown version */
  493.  
  494.         if (!hidekey && alg)
  495.         {    /* Don't bother trying if hidekey is false and alg is true */
  496.             fseek(f, (long)cert_length-1, SEEK_CUR);
  497.             return(-5);
  498.         }
  499.  
  500.         if (alg)    /* if secret components are encrypted... */
  501.         {    /* process encrypted CFB IV before reading secret components */
  502.             count = fread(iv,1,8,f);
  503.             if (count < 8)
  504.                 return(-4);    /* data corrupted, error return */
  505.             ideacfb(iv,8);
  506.             cert_length -= 8;    /* take IV length into account */
  507.         }
  508.  
  509.         /* Reset checksum before these reads */
  510.         mpi_checksum = 0;
  511.  
  512.         if (read_mpi(d,f,FALSE,hidekey) < 0)
  513.             return(-4);    /* data corrupted, error return */
  514.         if (read_mpi(p,f,FALSE,hidekey) < 0)
  515.             return(-4);    /* data corrupted, error return */
  516.         if (read_mpi(q,f,FALSE,hidekey) < 0)
  517.             return(-4);    /* data corrupted, error return */
  518.  
  519.         /* use register 'u' briefly as scratchpad */
  520.         mp_mult(u,p,q);    /* compare p*q against n */
  521.         if (mp_compare(n,u)!=0)    /* bad pass phrase? */
  522.             return(-5);    /* possible bad pass phrase, error return */
  523.         /* now read in real u */
  524.         if (read_mpi(u,f,FALSE,hidekey) < 0)
  525.             return(-4);    /* data corrupted, error return */
  526.  
  527.         /* Read checksum, compare with mpi_checksum */
  528.         fread (&chksum,1,sizeof(chksum),f);
  529.         convert(chksum);
  530.         if (chksum != mpi_checksum)
  531.             return(-5);    /* possible bad pass phrase */
  532.  
  533.         cert_length -= 1 + (countbytes(d)+2) + (countbytes(p)+2) 
  534.             + (countbytes(q)+2) + (countbytes(u)+2) + 2;
  535.  
  536.     }    /* secret key */
  537.     else /* not a secret key */
  538.     {    mp_init(d,0);
  539.         mp_init(p,0);
  540.         mp_init(q,0);
  541.         mp_init(u,0);
  542.     }
  543.  
  544.     if (cert_length != 0)
  545.     {    fprintf(pgpout,"\n\007Corrupted key.  Bad length, off by %d bytes.\n",
  546.             (int) cert_length);
  547.         return(-4);    /* data corrupted, error return */
  548.     }
  549.  
  550.     return(0);    /* normal return */
  551.  
  552. }    /* readkeypacket */
  553.  
  554.  
  555.  
  556. int getpublickey(boolean giveup, boolean showkey, char *keyfile,
  557.     long *file_position, int *pktlen, byte *keyID, byte *timestamp, 
  558.     byte *userid, unitptr n, unitptr e)
  559. /*    keyID contains key fragment we expect to find in keyfile.
  560.     If keyID is NULL, then userid contains a C string search target of
  561.     userid to find in keyfile.
  562.     keyfile is the file to begin search in, and it may be modified
  563.     to indicate true filename of where the key was found.  It can be
  564.     either a public key file or a secret key file.
  565.     file_position is returned as the byte offset within the keyfile
  566.     that the key was found at.  pktlen is the length of the key packet.
  567.     These values are for the key packet itself, not including any
  568.     following userid, control, signature, or comment packets.
  569.     giveup is TRUE iff we are just going to do a single file search only.
  570. */
  571. {
  572.     byte ctb;    /* returned by readkeypacket */
  573.     FILE *f;
  574.     int status;
  575.     boolean keyfound = FALSE;
  576.     boolean secret = FALSE;
  577.     char userid0[256];    /* C string format */
  578.     long fpos, userid_pos;
  579.  
  580.     userid0[0] = '\0';
  581.  
  582.     if (keyID==NULL)    /* then userid has search target */
  583.         strcpy(userid0,(char *)userid);
  584.  
  585. top:
  586.     default_extension(keyfile,PGP_EXTENSION);
  587.  
  588.     if (!file_exists(keyfile))
  589.     {    if (giveup)
  590.             return(-1);    /* give up, error return */
  591.         fprintf(pgpout,PSTR("\n\007Keyring file '%s' does not exist. "),keyfile);
  592.         goto nogood;
  593.     }
  594. #ifdef DEBUG
  595.     if (verbose) fprintf(pgpout,"\nSearching key ring file '%s'.\n",keyfile);
  596. #endif
  597.  
  598.     /* open file f for read, in binary (not text) mode...*/
  599. #ifdef VMS
  600.     if ((f = fopen(keyfile,"rb","ctx=stm")) == NULL)
  601. #else
  602.     if ((f = fopen(keyfile,"rb")) == NULL)
  603. #endif
  604.         return(-1);    /* error return */
  605.  
  606.     while (TRUE) 
  607.     {
  608.         fpos = ftell(f);
  609.         status = readkeypacket(f,FALSE,&ctb,timestamp,(char *)userid,n,e,
  610.                 NULL,NULL,NULL,NULL,NULL,NULL);
  611.         /* Note that readkeypacket has called set_precision */
  612.  
  613.         if (status == -1)    /* end of file */
  614.             break;
  615.  
  616.         if (status < -1)
  617.         {    fprintf(pgpout,PSTR("\n\007Could not read key from file '%s'.\n"),
  618.                 keyfile);
  619.             fclose(f);    /* close key file */
  620.             return(status);
  621.         }
  622.  
  623.         /* Remember packet position and size for last key packet */
  624.         if (is_key_ctb(ctb))
  625.         {    *file_position = fpos;
  626.             *pktlen = (int)(ftell(f) - fpos);
  627.             secret = is_ctb_type(ctb, CTB_CERT_SECKEY_TYPE);
  628.         }
  629.  
  630.         /* Only check for matches when we find a USERID packet */
  631.         if (ctb == CTB_USERID)
  632.         {    /* keyID contains key fragment.  Check it against n from keyfile. */
  633.             if (keyID!=NULL)
  634.                     keyfound = checkkeyID(keyID,n);
  635.             else
  636.             {    /* userid0 is already a C string */
  637.                 PascalToC((char *)userid);    /* for C string functions */
  638.                 /* Accept any matching subset */
  639.                 keyfound = userid_match((char *)userid,userid0);
  640.                 CToPascal((char *)userid);
  641.             }
  642.         }
  643.  
  644.         if (keyfound)
  645.         {    if (showkey)
  646.             {    PascalToC((char *)userid);    /* for display */
  647.                 fprintf(pgpout,PSTR("\nKey for user ID: %s\n"),EXTERNAL((char *)userid));
  648.                 fprintf(pgpout,PSTR("%d-bit key, Key ID %s, created %s\n"),
  649.                     countbits(n), key2IDstring(n), cdate((word32 *)timestamp) );
  650.                 CToPascal((char *)userid);    /* restore after display */
  651. #if 0
  652.                 if (keyID!=NULL)
  653.                 {    /* If a keyID match, display other user ID's */
  654.                     while (readkeypacket(f,FALSE,&ctb,NULL,(char *)userid0,
  655.                             NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL) == 0  &&
  656.                             !is_key_ctb(ctb))
  657.                     {    if (ctb == CTB_USERID)
  658.                         {    PascalToC ((char *)userid0);
  659.                             fprintf (pgpout,PSTR("Also known as: %s\n"),EXTERNAL(userid0));
  660.                         }
  661.                     }
  662.                 }
  663. #else    /* always show all userid's */
  664.                 userid_pos = fpos;
  665.                 if (keyID==NULL)
  666.                     fseek(f, *file_position + *pktlen, SEEK_SET);
  667.                 while (readkeypacket(f,FALSE,&ctb,NULL,(char *)userid0,
  668.                         NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL) == 0  &&
  669.                         !is_key_ctb(ctb))
  670.                 {    if (ctb == CTB_USERID)
  671.                     {    PascalToC ((char *)userid0);
  672.                         if (fpos != userid_pos)
  673.                             fprintf (pgpout,PSTR("Also known as: %s\n"),
  674.                                                 userid0);
  675.                     }
  676.                     fpos = ftell(f);
  677.                 }
  678. #endif
  679.             }
  680.             fseek(f, *file_position, SEEK_SET);
  681.             if (is_compromised(f))
  682.             {    fclose(f);
  683.                 return(1);
  684.             }
  685.             fclose(f);
  686.             return(0);    /* normal return */
  687.         }
  688.     }    /* while TRUE */
  689.  
  690.     fclose(f);    /* close key file */
  691.  
  692.     if (giveup)
  693.         return(-1);    /* give up, error return */
  694.  
  695.     if (keyID!=NULL)
  696.     {
  697.         fprintf(pgpout,PSTR("\n\007Key matching expected Key ID %s not found in file '%s'.\n"),
  698.             keyIDstring(keyID),keyfile);
  699.     }
  700.     else
  701.     {    fprintf(pgpout,PSTR("\n\007Key matching userid '%s' not found in file '%s'.\n"),
  702.             EXTERNAL(userid0),keyfile);
  703.     }
  704.  
  705. nogood:
  706.     if (giveup)
  707.         return(-1);    /* give up, error return */
  708.  
  709.     if (secret)
  710.     {    /* Look in public key file and see if it's there. */
  711.         char keyfilename[MAX_PATH];    /* for getpublickey */
  712.         buildfilename(keyfilename,PUBLIC_KEYRING_FILENAME);
  713.         if (getpublickey(TRUE,FALSE,keyfilename,file_position,pktlen,
  714.                 keyID,timestamp,userid,n,e) >= 0)
  715.         {    PascalToC((char * )userid);
  716.             fprintf(pgpout,PSTR("\nThis message can only be read by:\n"));
  717.             fprintf(pgpout,"\"%s\"\n\n",EXTERNAL((char *)userid));
  718.             CToPascal((char *)userid);
  719.         }
  720.         fprintf(pgpout,PSTR("Enter secret key filename: "));
  721.     }
  722.     else
  723.         fprintf(pgpout,PSTR("Enter public key filename: "));
  724.  
  725.     getstring(keyfile,59,TRUE);    /* echo keyboard input */
  726.     if (strlen(keyfile) > 0)
  727.         goto top;
  728.  
  729.     return(-1);    /* give up, error return */
  730.  
  731. }    /* getpublickey */
  732.  
  733. int getpubuserid(char *keyfile, long key_position, byte *userid,
  734.     long *userid_position, int *userid_len)
  735. /*  Start at key_position in keyfile, and scan for the key packet
  736.     that contains userid.  Return userid_position and userid_len.
  737.     Return 0 if OK, -1 on error.  Userid should be a C string.
  738. */
  739. {
  740.     byte ctb;    /* returned by readkeypacket */
  741.     FILE *f;
  742.     int status;
  743.     char userid0[256];    /* C string format */
  744.     long fpos;
  745.  
  746.     /* open file f for read, in binary (not text) mode...*/
  747. #ifdef VMS
  748.     if ((f = fopen(keyfile,"rb","ctx=stm")) == NULL)
  749. #else
  750.     if ((f = fopen(keyfile,"rb")) == NULL)
  751. #endif
  752.         return(-1);    /* error return */
  753.  
  754.     /* Start off at correct location */
  755.     fseek (f, key_position, SEEK_SET);
  756.     (void)nextkeypacket(f, &ctb);    /* Skip key */
  757.     while (TRUE) 
  758.     {
  759.         fpos = ftell(f);
  760.         status = readkeypacket(f,FALSE,&ctb,NULL,(char *)userid0,NULL,NULL,
  761.                 NULL,NULL,NULL,NULL,NULL,NULL);
  762.  
  763.         if (status < 0  ||  is_key_ctb(ctb))
  764.             break;
  765.  
  766.         /* Only check for matches when we find a USERID packet */
  767.         if (ctb == CTB_USERID)
  768.         {    /* userid is already a C string */
  769.             PascalToC((char *)userid0);    /* for C string functions */
  770.             /* Accept any matching subset */
  771.             if (userid_match((char *)userid0, (char *) userid))
  772.             {    *userid_position = fpos;
  773.                 *userid_len = ftell(f) - fpos;
  774.                 fclose(f);
  775.                 return(0);    /* normal return */
  776.             }
  777.         }
  778.     }    /* while TRUE */
  779.  
  780.     fclose(f);    /* close key file */
  781.     return(-1);    /* give up, error return */
  782. }    /* getpubuserid */
  783.  
  784.  
  785. int getpubusersig(char *keyfile, long user_position, byte *sigkeyID,
  786.     long *sig_position, int *sig_len)
  787. /*  Start at user_position in keyfile, and scan for the signature packet
  788.     that matches sigkeyID.  Return sig_position and sig_len.
  789.     Return 0 if OK, -1 on error.
  790. */
  791. {
  792.     byte ctb;    /* returned by readkeypacket */
  793.     FILE *f;
  794.     int status;
  795.     byte keyID0[KEYFRAGSIZE];
  796.     long fpos;
  797.  
  798.     /* open file f for read, in binary (not text) mode...*/
  799. #ifdef VMS
  800.     if ((f = fopen(keyfile,"rb","ctx=stm")) == NULL)
  801. #else
  802.     if ((f = fopen(keyfile,"rb")) == NULL)
  803. #endif
  804.         return(-1);    /* error return */
  805.  
  806.     /* Start off at correct location */
  807.     fseek (f, user_position, SEEK_SET);
  808.     (void)nextkeypacket(f, &ctb);    /* Skip userid packet */
  809.     while (TRUE) 
  810.     {
  811.         fpos = ftell(f);
  812.         status = readkeypacket(f,FALSE,&ctb,NULL,NULL,NULL,NULL,
  813.                 NULL,NULL,NULL,NULL,keyID0,NULL);
  814.  
  815.         if (status < 0  ||  is_key_ctb(ctb)  ||  ctb==CTB_USERID)
  816.             break;
  817.  
  818.         /* Only check for matches when we find a signature packet */
  819.         if (is_ctb_type(ctb,CTB_SKE_TYPE))
  820.         {    if (equal_buffers(sigkeyID,keyID0,KEYFRAGSIZE))
  821.             {    *sig_position = fpos;
  822.                 *sig_len = ftell(f) - fpos;
  823.                 fclose(f);
  824.                 return(0);    /* normal return */
  825.             }
  826.         }
  827.     }    /* while TRUE */
  828.  
  829.     fclose(f);    /* close key file */
  830.     return(-1);    /* give up, error return */
  831. }    /* getpubusersig */
  832.  
  833.  
  834. int getsecretkey(boolean giveup, boolean showkey, char *keyfile, byte *keyID,
  835.     byte *timestamp, char *passp, boolean *hkey,
  836.     byte *userid, unitptr n, unitptr e, unitptr d, unitptr p, unitptr q,
  837.     unitptr u)
  838. /*    keyID contains key fragment we expect to find in keyfile.
  839.     If keyID is NULL, then userid contains search target of
  840.     userid to find in keyfile.
  841.     giveup controls whether we ask the user for the name of the
  842.     secret key file on failure.  showkey controls whether we print
  843.     out the key information when we find it.  keyfile, if non-NULL,
  844.     is the name of the secret key file; if NULL, we use the
  845.     default.  passp and hkey, if non-NULL, get returned with a copy
  846.     of the pass phrase and hidekey variables.
  847. */
  848. {
  849.     byte ctb;    /* returned by readkeypacket */
  850.     FILE *f;
  851.     char keyfilename[MAX_PATH];    /* for getpublickey */
  852.     long file_position;
  853.     int pktlen;    /* unused, just to satisfy getpublickey */
  854.     int status;
  855.     boolean hidekey = FALSE;    /* TRUE iff secret key is encrypted */
  856.     char passphrase[256];
  857.     word16 iv[4];        /* initialization vector for encryption */
  858.     byte ideakey[16];
  859.     char *envkey;
  860.     int guesses = 3;
  861.  
  862.     if (keyfile == NULL)
  863.     {    /* use default pathname */
  864.         buildfilename(keyfilename,SECRET_KEYRING_FILENAME);
  865.         keyfile = keyfilename;
  866.     }
  867.  
  868.     status = getpublickey(giveup, showkey, keyfile, &file_position, &pktlen,
  869.             keyID, timestamp, userid, n, e);
  870.     if (status < 0)
  871.         return(status);    /* error return */
  872.  
  873.  
  874.     /* open file f for read, in binary (not text) mode...*/
  875. #ifdef VMS
  876.     if ((f = fopen(keyfile,"rb","ctx=stm")) == NULL)
  877. #else
  878.     if ((f = fopen(keyfile,"rb")) == NULL)
  879. #endif
  880.         return(-1);    /* error return */
  881.  
  882.     /* First guess is null password, so hidekey is FALSE */
  883.  
  884.     do    /* until good password */
  885.     {    if (hkey != NULL)
  886.             *hkey = hidekey;
  887.         /* Initialize IDEA key */
  888.         if (hidekey)
  889.         {    if (passp != NULL)
  890.                 strcpy (passp, passphrase); /* Save phrase for caller */
  891.             fill0(iv,8);
  892.             initcfb_idea(iv,ideakey,TRUE);
  893.         }
  894.         fseek(f,file_position,SEEK_SET); /* reposition file to key */
  895.         status = readkeypacket(f,hidekey,&ctb,timestamp,(char *)userid,
  896.                         n,e,d,p,q,u,NULL,NULL);
  897.         if (hidekey)
  898.             close_idea();    /* Release resources */
  899.  
  900.         burn((byteptr)passphrase);    /* burn sensitive data on stack */
  901.  
  902.         if (status == -5)    /* bad pass phrase status */
  903.         {    if (guesses!=3)    /* not first guess of null password? */
  904.                 fprintf(pgpout,PSTR("\n\007Error:  Bad pass phrase.\n"));
  905.             if (!hidekey && (envkey = getenv ("PGPPASS")) != NULL)
  906.             { /* Try environment variable second */
  907.                 strncpy (passphrase, envkey, sizeof(passphrase)-1);
  908.                 hashpass (passphrase, strlen(passphrase), ideakey);
  909.                 hidekey = TRUE;
  910.                 continue;
  911.             }
  912.             if (--guesses)    /* not ran out of guesses yet */
  913.             {    fprintf(pgpout,PSTR("\nYou need a pass phrase to unlock your RSA secret key. "));
  914.                 if (!showkey && guesses == 2)
  915.                 {    /* let user know for which key he should type his password */
  916.                     PascalToC((char *)userid);
  917.                     fprintf(pgpout, PSTR("\nKey for user ID \"%s\"\n"), EXTERNAL((char *)userid));
  918.                     CToPascal((char *)userid);
  919.                 }
  920.                 hidekey = (getideakey(passphrase, (char *) ideakey, 1) > 0);
  921.                 continue;    /* take it from the top */
  922.             }    /* more guesses to go */
  923.         }
  924.         if (status < 0)
  925.         {    fprintf(pgpout,PSTR("\n\007Could not read key from file '%s'.\n"),
  926.                 keyfile);
  927.             fclose(f);    /* close key file */
  928.             return(-1);
  929.         }
  930.     }    while (status < 0);    /* until key reads OK, with good password */
  931.  
  932.     fclose(f);    /* close key file */
  933.  
  934.     /* Note that readkeypacket has called set_precision */
  935.  
  936.     if (d != NULL)        /* No effective check of pass phrase if d is NULL */
  937.     {    if (!hidekey)
  938.             fprintf(pgpout,PSTR("\nAdvisory warning: This RSA secret key is not protected by a passphrase.\n"));
  939.         else
  940.             fprintf(pgpout,PSTR("Pass phrase is good.  "));
  941.  
  942.         if (testeq(d,0))    /* didn't get secret key components */
  943.         {    fprintf(pgpout,PSTR("\n\007Key file '%s' is not a secret key file.\n"),keyfile);
  944.             return(-1);
  945.         }
  946.     }
  947.  
  948.     return(0);    /* normal return */
  949.  
  950. }    /* getsecretkey */
  951.  
  952.  
  953. int is_compromised(FILE *f)
  954. /* check if a key has a compromise certificate, file pointer must
  955.    be positioned at or right after the key packet.
  956. */
  957. {
  958.     long pos, savepos;
  959.     byte class, ctb;
  960.     int cert_len;
  961.     int status = 0;
  962.  
  963.     pos = savepos = ftell(f);
  964.  
  965.     nextkeypacket(f, &ctb);
  966.     if (is_key_ctb(ctb))
  967.     {    pos = ftell(f);
  968.         nextkeypacket(f, &ctb);
  969.     }
  970.     if (ctb != CTB_KEYCTRL)
  971.         fseek(f, pos, SEEK_SET);
  972.  
  973.     /* file pointer now positioned where compromise cert. should be */
  974.     if (fread(&ctb, 1, 1, f) != 1)
  975.     {    status = -1;
  976.         goto ex;
  977.     }
  978.     
  979.     if (is_ctb_type(ctb, CTB_SKE_TYPE))
  980.     {
  981.         cert_len = getpastlength(ctb, f);
  982.         if (cert_len > MAX_SIGCERT_LENGTH)    /* Huge packet length */
  983.         {    status = -1;
  984.             goto ex;
  985.         }
  986.  
  987.         /* skip version and mdlen byte */
  988.         fseek(f, 2L, SEEK_CUR);
  989.         if (fread(&class, 1, 1, f) != 1)
  990.         {    status = -1;
  991.             goto ex;
  992.         }
  993.         status = (class == KC_SIGNATURE_BYTE);
  994.     }
  995. ex:
  996.     fseek(f, savepos, SEEK_SET);
  997.     return(status);
  998. }
  999.  
  1000.  
  1001. /*    Alfred Hitchcock coined the term "mcguffin" for the generic object 
  1002.     being sought in his films-- the diamond, the microfilm, etc. 
  1003. */
  1004.  
  1005. int view_keyring(char *mcguffin, char *ringfile, boolean show_signatures)
  1006. /*    Lists all entries in keyring that have mcguffin string in userid.
  1007.     mcguffin is a null-terminated C string.
  1008. */
  1009. {    FILE *f;
  1010.     byte ctb, keyctb;
  1011.     long fpr;
  1012.     int pktlenr;
  1013.     int status;
  1014.     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
  1015.     byte keyID[KEYFRAGSIZE];
  1016.     byte sigkeyID[KEYFRAGSIZE];
  1017.     byte userid[256];        /* key certificate userid */
  1018.     char dfltring[MAX_PATH];
  1019.     word32 tstamp;
  1020.     byte *timestamp = (byte *) &tstamp;        /* key certificate timestamp */
  1021.     int keycounter = 0;
  1022.     int firstuser = 0;
  1023.     int compromised = 0;
  1024.  
  1025.     /* Default keyring to check signature ID's */
  1026.     buildfilename(dfltring,PUBLIC_KEYRING_FILENAME);
  1027.  
  1028.     /* open file f for read, in binary (not text) mode...*/
  1029. #ifdef VMS
  1030.     if ((f = fopen(ringfile,"rb","ctx=stm")) == NULL)
  1031. #else
  1032.     if ((f = fopen(ringfile,"rb")) == NULL)
  1033. #endif
  1034.     {    fprintf(pgpout,PSTR("\n\007Can't open key ring file '%s'\n"),ringfile);
  1035.         return(-1);
  1036.     }
  1037.  
  1038. /*    Here's a good format for display of key or signature certificates:
  1039. Type bits/keyID   Date       User ID
  1040. pub  1024/xxxxxx yyyy-mm-dd  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  1041. sec   512/xxxxxx yyyy-mm-dd  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  1042. sig   384/xxxxxx yyyy-mm-dd  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  1043. */
  1044.  
  1045.     fprintf(pgpout,PSTR("\nKey ring: '%s'"),ringfile);
  1046.     if (mcguffin && strlen(mcguffin) > 0)
  1047.         fprintf(pgpout,PSTR(", looking for user ID \"%s\"."),EXTERNAL(mcguffin));
  1048.     fprintf(pgpout,PSTR("\nType bits/keyID   Date       User ID\n"));
  1049.     for ( ; ; )
  1050.     {
  1051.         status = readkeypacket(f,FALSE,&ctb,timestamp,(char *)userid,n,e,
  1052.                 NULL,NULL,NULL,NULL,sigkeyID,NULL);
  1053.         /* Note that readkeypacket has called set_precision */
  1054.         if (status== -1)
  1055.         {    status = 0;
  1056.             break;    /* eof reached */
  1057.         }
  1058.         if (status < 0)
  1059.         {    fprintf(pgpout,PSTR("\n\007Could not read key from file '%s'.\n"),
  1060.                 ringfile);
  1061.             break;
  1062.         }
  1063.  
  1064.         if (is_key_ctb(ctb))
  1065.         {    keycounter++;
  1066.             firstuser = 1;
  1067.             keyctb = ctb;
  1068.             compromised = is_compromised(f);
  1069.         }
  1070.  
  1071.         if (ctb != CTB_USERID  &&  !is_ctb_type(ctb, CTB_SKE_TYPE))
  1072.             continue;
  1073.         extract_keyID(keyID, n);
  1074.         PascalToC((char *)userid);
  1075.  
  1076.         if (userid_match((char *)userid,mcguffin))
  1077.         {
  1078.             if (ctb == CTB_USERID)
  1079.             {    if (firstuser)
  1080.                 {    if (is_ctb_type(keyctb,CTB_CERT_PUBKEY_TYPE))
  1081.                         fprintf(pgpout,"pub  ");
  1082.                     else if (is_ctb_type(keyctb,CTB_CERT_SECKEY_TYPE))
  1083.                         fprintf(pgpout,"sec  ");
  1084.                     else
  1085.                         fprintf(pgpout,"???  ");
  1086.                     fprintf(pgpout,"%4d/%s %s  ",
  1087.                         countbits(n),keyIDstring(keyID),cdate(&tstamp));
  1088.                 }
  1089.                 else
  1090.                     fprintf(pgpout,"                             ");
  1091.                 if (compromised && firstuser)
  1092.                 {    fprintf(pgpout, PSTR("*** KEY REVOKED ***\n"));
  1093.                     fprintf(pgpout,"                             ");
  1094.                 }
  1095.                 firstuser = 0;
  1096.                 fprintf(pgpout,"%s\n",EXTERNAL((char *)userid));
  1097.             }
  1098.             else if (show_signatures && !(firstuser && compromised))    /* Must be sig cert */
  1099.             {    fprintf(pgpout,"sig       ");
  1100.                 showkeyID(sigkeyID);
  1101.                 fprintf(pgpout,"              "); /* Indent userid */
  1102.                 if (getpublickey(TRUE, FALSE, ringfile, &fpr, &pktlenr,
  1103.                                  sigkeyID, timestamp, userid, n, e)>=0 ||
  1104.                     getpublickey(TRUE, FALSE, dfltring, &fpr, &pktlenr,
  1105.                                  sigkeyID, timestamp, userid, n, e)>=0)
  1106.                 {    PascalToC((char *)userid);
  1107.                     fprintf(pgpout,"%s\n",EXTERNAL((char *)userid));
  1108.                 }
  1109.                 else
  1110.                     fprintf(pgpout,PSTR("(Unknown signator, can't be checked)\n"));
  1111.             } /* printing a sig cert */
  1112.         }    /* if it has mcguffin */
  1113.     }    /* loop for all packets */
  1114.  
  1115.     fclose(f);    /* close key file */
  1116.     fprintf(pgpout,PSTR("%d key(s) examined.\n"),keycounter);
  1117.  
  1118.     return(status);    /* normal return */
  1119.  
  1120. }    /* view_keyring */
  1121.  
  1122.  
  1123. int dokeycheck(char *mcguffin, char *ringfile, byte *chk_keyID)
  1124. /*    Lists all entries in keyring that have mcguffin string in userid.
  1125.     mcguffin is a null-terminated C string.
  1126. */
  1127. {    FILE *f, *fixedf;
  1128.     byte ctb, keyctb;
  1129.     long fpsig, fpkey, fixpos = 0;
  1130.     int status, sigstatus;
  1131.     int keypktlen, sigpktlen;
  1132.     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
  1133.     byte keyID[KEYFRAGSIZE];
  1134.     byte sigkeyID[KEYFRAGSIZE];
  1135.     byte keyuserid[256];        /* key certificate userid */
  1136.     byte siguserid[256];        /* sig certificate userid */
  1137.     char dfltring[MAX_PATH];
  1138.     char *tempring;
  1139.     word32 tstamp;
  1140.     byte *timestamp = (byte *) &tstamp;        /* key certificate timestamp */
  1141.     word32 sigtstamp;
  1142.     byte *sigtimestamp = (byte *) &sigtstamp;
  1143.     byte sigclass;
  1144.     int firstuser = 0;
  1145.     int compromised = 0;
  1146.     boolean failed=FALSE;
  1147.  
  1148.     /* Default keyring to check signature ID's */
  1149.     buildfilename(dfltring,PUBLIC_KEYRING_FILENAME);
  1150.  
  1151.     /* open file f for read, in binary (not text) mode...*/
  1152. #ifdef VMS
  1153.     if ((f = fopen(ringfile,"rb","ctx=stm")) == NULL)
  1154. #else
  1155.     if ((f = fopen(ringfile,"rb")) == NULL)
  1156. #endif
  1157.     {    fprintf(pgpout,PSTR("\n\007Can't open key ring file '%s'\n"),ringfile);
  1158.         return(-1);
  1159.     }
  1160.  
  1161. /*    Here's a good format for display of key or signature certificates:
  1162. Type bits/keyID   Date       User ID
  1163. pub  1024/xxxxxx yyyy-mm-dd  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  1164. sec   512/xxxxxx yyyy-mm-dd  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  1165. sig   384/xxxxxx yyyy-mm-dd  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  1166. */
  1167.  
  1168.     if (!chk_keyID)
  1169.     {    fprintf(pgpout,PSTR("\nKey ring: '%s'"),ringfile);
  1170.         if (mcguffin && strlen(mcguffin) > 0)
  1171.             fprintf(pgpout,PSTR(", looking for user ID \"%s\"."),EXTERNAL(mcguffin));
  1172.         fprintf(pgpout,PSTR("\nType bits/keyID   Date       User ID\n"));
  1173.     }
  1174.     for ( ; ; )
  1175.     {    long fpos = ftell(f);
  1176.         status = readkeypacket(f,FALSE,&ctb,timestamp,(char *)keyuserid,n,e,
  1177.                 NULL,NULL,NULL,NULL,sigkeyID,NULL);
  1178.         /* Note that readkeypacket has called set_precision */
  1179.         if (status== -1 ) break;    /* eof reached */
  1180.         if (status < 0)
  1181.         {    fprintf(pgpout,PSTR("\n\007Could not read key from file '%s'.\n"),
  1182.                 ringfile);
  1183.             fclose(f);    /* close key file */
  1184.             return(-1);
  1185.         }
  1186.  
  1187.         if (is_key_ctb(ctb))
  1188.         {    firstuser = 1;
  1189.             keyctb = ctb;
  1190.             fpkey = fpos;
  1191.             keypktlen = ftell(f) - fpkey;
  1192.             extract_keyID(keyID, n);
  1193.             compromised = is_compromised(f);
  1194.         }
  1195.  
  1196.         if (ctb != CTB_USERID  &&  !is_ctb_type(ctb, CTB_SKE_TYPE))
  1197.             continue;
  1198.         if (ctb == CTB_USERID)
  1199.             PascalToC((char *)keyuserid);
  1200.  
  1201.         if (chk_keyID || userid_match((char *)keyuserid,mcguffin))
  1202.         {
  1203.             if (ctb == CTB_USERID)
  1204.             {    if (chk_keyID)
  1205.                     continue;
  1206.                 if (firstuser)
  1207.                 {    if (is_ctb_type(keyctb,CTB_CERT_PUBKEY_TYPE))
  1208.                         fprintf(pgpout,"pub  ");
  1209.                     else if (is_ctb_type(keyctb,CTB_CERT_SECKEY_TYPE))
  1210.                         fprintf(pgpout,"sec  ");
  1211.                     else
  1212.                         fprintf(pgpout,"???  ");
  1213.                     fprintf(pgpout,"%4d/%s %s  ",
  1214.                         countbits(n),keyIDstring(keyID),cdate(&tstamp));
  1215.                 }
  1216.                 else
  1217.                     fprintf(pgpout,"                             ");
  1218.                 if (compromised && firstuser)
  1219.                 {    fprintf(pgpout, PSTR("*** KEY REVOKED ***\n"));
  1220.                     fprintf(pgpout,"                             ");
  1221.                 }
  1222.                 firstuser = 0;
  1223.                 fprintf(pgpout,"%s\n",EXTERNAL((char *)keyuserid));
  1224.             }
  1225.             else /* Must be sig cert */
  1226.             {    /* Try checking signature on either this ring or dflt ring */
  1227.                 if (chk_keyID && memcmp(chk_keyID, sigkeyID, KEYFRAGSIZE))
  1228.                     continue;    /* only check signatures from chk_keyID */
  1229.                 fpsig = fpos;
  1230.                 sigpktlen = ftell(f) - fpsig;
  1231.                 CToPascal((char *)keyuserid);
  1232.                 sigstatus = check_key_sig (f, fpkey, keypktlen, (char *) keyuserid,
  1233.                     f, fpsig, ringfile, (char *) siguserid, sigtimestamp, &sigclass);
  1234.                 if (sigstatus == -1  &&  strcmp(ringfile,dfltring) != 0)
  1235.                     sigstatus = check_key_sig (f, fpkey, keypktlen, (char *) keyuserid,
  1236.                         f, fpsig, dfltring, (char *) siguserid, sigtimestamp, &sigclass);
  1237.                 PascalToC((char *)keyuserid);
  1238.                 fseek (f, fpsig+sigpktlen, SEEK_SET);
  1239.                 if (sigclass == KC_SIGNATURE_BYTE)
  1240.                     fprintf(pgpout,"com");
  1241.                 else
  1242.                     fprintf(pgpout,"sig");
  1243.                 if (sigstatus >= 0)
  1244.                     fprintf(pgpout,"!      ");
  1245.                 else if (sigstatus == -1)
  1246.                     fprintf(pgpout,"?      ");
  1247.                 else
  1248.                     fprintf(pgpout,"*      ");
  1249.                 showkeyID(sigkeyID);
  1250.                 if (sigstatus >= 0)
  1251.                 {    PascalToC((char *) siguserid);
  1252.                     fprintf(pgpout," %s  ",cdate(&sigtstamp));
  1253.                     if (sigclass != KC_SIGNATURE_BYTE)
  1254.                         fprintf(pgpout, "  ");
  1255.                     fprintf(pgpout,"%s\n", EXTERNAL((char *)siguserid));
  1256.                 }
  1257.                 else if (sigstatus == -1)
  1258.                 {    fprintf(pgpout,"              ");
  1259.                     fprintf(pgpout,PSTR("(Unknown signator, can't be checked)\n"));
  1260.                 }
  1261.                 else
  1262.                 {    fprintf(pgpout,"              ");
  1263.                     fprintf(pgpout,PSTR("\007***** BAD SIGNATURE! *****\n"));
  1264.                     if (!failed)
  1265.                     {    /* first bad signature: create scratch file */
  1266.                         tempring = tempfile(TMP_TMPDIR);
  1267.                         fixedf = fopenbin(tempring, "w");
  1268.                         failed = TRUE;
  1269.                     }
  1270.                     if (fixedf != NULL)
  1271.                     {
  1272.                         copyfilepos(f, fixedf, fpsig - fixpos, fixpos);
  1273.                         fseek(f, fpsig+sigpktlen, SEEK_SET);
  1274.                         if (nextkeypacket(f, &ctb) < 0 || ctb != CTB_KEYCTRL)
  1275.                             fseek(f, fpsig+sigpktlen, SEEK_SET);
  1276.                         fixpos = ftell(f);
  1277.                     }
  1278.                 }
  1279.             } /* checking a signature */
  1280.         }    /* if it has mcguffin */
  1281.     }    /* loop for all packets */
  1282.  
  1283.     if (!chk_keyID)
  1284.         fputc('\n',pgpout);
  1285.  
  1286.     if (failed)
  1287.     {
  1288.         copyfilepos(f, fixedf, -1L, fixpos);
  1289.         fclose(fixedf);
  1290.         fprintf(pgpout, PSTR("Remove bad signatures (Y/n)? "));
  1291.         if (getyesno('y'))
  1292.         {
  1293.             savetempbak(tempring, ringfile);
  1294.             failed = 0;
  1295.         }
  1296.     }
  1297.     fclose(f);    /* close key file */
  1298.  
  1299.     return(failed?-1:0);    /* normal return */
  1300.  
  1301. }    /* dokeycheck */
  1302.  
  1303. int backup_rename(char *scratchfile, char *destfile)
  1304. {    /* rename scratchfile to destfile after making a backup file */
  1305.     char bakfile[MAX_PATH];
  1306.  
  1307.     if (strcmp(destfile, SCRATCH_KEYRING_PATH) == 0 ||
  1308.             is_tempfile(destfile))
  1309.     {
  1310.         remove(destfile);
  1311.     }
  1312.     else
  1313.     {    if (file_exists(destfile))
  1314.         {
  1315.             strcpy(bakfile, destfile);
  1316.             force_extension(bakfile, BAK_EXTENSION);
  1317.             remove(bakfile);
  1318.             rename(destfile, bakfile);
  1319.         }
  1320.     }
  1321.     return(rename2(scratchfile, destfile));
  1322. }
  1323.  
  1324. int remove_sigs(char *mcguffin, char*ringfile)
  1325. /* Lists all signatures for keys with specified mcguffin string, and asks
  1326.  * if they should be removed.
  1327.  */
  1328. {    FILE *f, *g;
  1329.     byte ctb;
  1330.     long fp, fpr, fpuser;
  1331.     int packetlength, pktlenr;
  1332.     int status;
  1333.     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
  1334.     byte sigkeyID[KEYFRAGSIZE];
  1335.     byte userid[256];        /* key certificate userid */
  1336.     char dfltring[MAX_PATH];
  1337.     word32 tstamp;
  1338.     byte *timestamp = (byte *) &tstamp;        /* key certificate timestamp */
  1339.     int nsigs = 0, nremoved = 0;
  1340.     int keeping;
  1341.  
  1342.     /* Default keyring to check signature ID's */
  1343.     buildfilename(dfltring,PUBLIC_KEYRING_FILENAME);
  1344.  
  1345.     if (build_path(SCRATCH_KEYRING_PATH,SCRATCH_KEYRING_FILENAME,ringfile)<0)
  1346.         return(-1);    /* Error, file path too long */
  1347.  
  1348.     if (!mcguffin  ||  strlen(mcguffin) == 0)
  1349.         return(-1);
  1350.  
  1351.     strcpy((char *)userid,mcguffin);
  1352.  
  1353.     fprintf(pgpout,PSTR("\nRemoving signatures from userid '%s' in key ring '%s'\n"),
  1354.                 EXTERNAL(mcguffin), ringfile);
  1355.  
  1356.     status = getpublickey(TRUE, TRUE, ringfile, &fp, &packetlength, NULL, timestamp, userid, n, e);
  1357.     if (status < 0)
  1358.     {    fprintf(pgpout,PSTR("\n\007Key not found in key ring '%s'.\n"),ringfile);
  1359.         return(0);    /* normal return */
  1360.     }
  1361.  
  1362.     strcpy((char *)userid,mcguffin);
  1363.     getpubuserid (ringfile, fp, userid, &fpuser, &packetlength);
  1364.     packetlength += fpuser - fp;
  1365.  
  1366.     /* open file f for read, in binary (not text) mode...*/
  1367. #ifdef VMS
  1368.     if ((f = fopen(ringfile,"rb","ctx=stm","ctx=stm")) == NULL)
  1369. #else
  1370.     if ((f = fopen(ringfile,"rb")) == NULL)
  1371. #endif
  1372.     {    fprintf(pgpout,PSTR("\n\007Can't open key ring file '%s'\n"),ringfile);
  1373.         return(-1);
  1374.     }
  1375.  
  1376.     /* Count signatures */
  1377.     fseek (f, fp+packetlength, SEEK_SET);
  1378.     for ( ; ; )
  1379.     {    status = nextkeypacket(f, &ctb);
  1380.         if (status < 0  ||  is_key_ctb(ctb)  ||  ctb==CTB_USERID)
  1381.             break;
  1382.         if (is_ctb_type(ctb,CTB_SKE_TYPE))
  1383.             ++nsigs;
  1384.     }
  1385.         
  1386.     rewind(f);
  1387.  
  1388.     if (nsigs == 0)
  1389.     {    fprintf (pgpout,PSTR("\nKey has no signatures to remove.\n"));
  1390.         fclose (f);
  1391.         return (0);        /* Normal return */
  1392.     }
  1393.  
  1394.     fprintf (pgpout, PSTR("\nKey has %d signature(s):\n"), nsigs);
  1395.  
  1396.     remove(SCRATCH_KEYRING_PATH);
  1397.     /* open file g for writing, in binary (not text) mode...*/
  1398. #ifdef VMS
  1399.     if ((g = fopen(SCRATCH_KEYRING_PATH,"wb","ctx=stm")) == NULL)
  1400. #else
  1401.     if ((g = fopen(SCRATCH_KEYRING_PATH,"wb")) == NULL)
  1402. #endif
  1403.     {    fclose(f);
  1404.         return(-1);
  1405.     }
  1406.     copyfile(f,g,fp+packetlength);    /* copy file f to g up through key */
  1407.  
  1408.     /* Now print out any following sig certs */
  1409.     keeping = 1;
  1410.     for ( ; ; )
  1411.     {    fp = ftell(f);
  1412.         status = readkeypacket(f, FALSE, &ctb, NULL, NULL, NULL, NULL,
  1413.                 NULL,NULL,NULL,NULL,sigkeyID,NULL);
  1414.         packetlength = ftell(f) - fp;
  1415.         if (status < 0  ||  is_key_ctb(ctb)  ||  ctb==CTB_USERID)
  1416.             break;
  1417.         if (is_ctb_type(ctb,CTB_SKE_TYPE))
  1418.         {    fprintf(pgpout,"sig      ");
  1419.             showkeyID(sigkeyID);
  1420.             fprintf(pgpout,"              "); /* Indent userid */
  1421.             if (getpublickey(TRUE, FALSE, ringfile, &fpr, &pktlenr,
  1422.                              sigkeyID, timestamp, userid, n, e)>=0 ||
  1423.                 getpublickey(TRUE, FALSE, dfltring, &fpr, &pktlenr,
  1424.                              sigkeyID, timestamp, userid, n, e)>=0)
  1425.             {    PascalToC((char *)userid);
  1426.                 fprintf(pgpout,"%s\n",EXTERNAL((char *)userid));
  1427.             }
  1428.             else
  1429.                 fprintf(pgpout,PSTR("(Unknown signator, can't be checked)\n"));
  1430.             fprintf(pgpout, PSTR("Remove this signature (y/N)? "));
  1431.             if (!(keeping=!getyesno('n')))
  1432.                 ++nremoved;
  1433.         }
  1434.         if (keeping)
  1435.             copyfilepos (f, g, packetlength, fp);
  1436.     }    /* scanning sig certs */
  1437.     copyfilepos (f, g, -1L, fp);        /* Copy rest of file */
  1438.  
  1439.     fclose(g);    /* close scratch file */
  1440.     fclose(f);    /* close key file */
  1441.     backup_rename(SCRATCH_KEYRING_PATH,ringfile);
  1442.     if (nremoved == 0)
  1443.         fprintf(pgpout,PSTR("\nNo key signatures removed.\n"));
  1444.     else
  1445.         fprintf(pgpout,PSTR("\n%d key signature(s) removed.\n"), nremoved);
  1446.  
  1447.     return(0);    /* normal return */
  1448.  
  1449. }    /* remove_sigs */
  1450.  
  1451.  
  1452. int remove_from_keyring(byte *keyID, char *mcguffin, char *ringfile)
  1453. /*    Remove the first entry in key ring that has mcguffin string in userid.
  1454.     Or it removes the first matching keyID from the ring.
  1455.     A non-NULL keyID takes precedence over a mcguffin specifier.
  1456.     mcguffin is a null-terminated C string.
  1457. */
  1458. {
  1459.     FILE *f;
  1460.     FILE *g;
  1461.     long fp, nfp;
  1462.     int packetlength;
  1463.     byte ctb;
  1464.     int status;
  1465.     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
  1466.     byte userid[256];        /* key certificate userid */
  1467.     word32 tstamp; byte *timestamp = (byte *) &tstamp;        /* key certificate timestamp */
  1468.     int userids;
  1469.     boolean rmuserid = FALSE;
  1470.  
  1471.     default_extension(ringfile,PGP_EXTENSION);
  1472.     if (build_path(SCRATCH_KEYRING_PATH,SCRATCH_KEYRING_FILENAME,ringfile)<0)
  1473.         return(-1);    /* Error, file path too long */
  1474.  
  1475.     if ((keyID==NULL) && (!mcguffin  ||  strlen(mcguffin)==0))
  1476.         return(-1); /* error, null mcguffin will match everything */
  1477.  
  1478.     if (mcguffin)
  1479.         strcpy((char *)userid,mcguffin);
  1480.  
  1481.     fprintf(pgpout,PSTR("\nRemoving from key ring: '%s'"),ringfile);
  1482.     if (mcguffin  &&  strlen(mcguffin) > 0)
  1483.         fprintf(pgpout,PSTR(", userid \"%s\".\n"),EXTERNAL(mcguffin));
  1484.  
  1485.     status = getpublickey(TRUE, TRUE, ringfile, &fp, &packetlength, NULL, timestamp, userid, n, e);
  1486.     if (status < 0)
  1487.     {    fprintf(pgpout,PSTR("\n\007Key not found in key ring '%s'.\n"),ringfile);
  1488.         return(0);    /* normal return */
  1489.     }
  1490.  
  1491.     /* Now add to packetlength the subordinate following certificates */
  1492. #ifdef VMS
  1493.     if ((f = fopen(ringfile,"rb","ctx=stm")) == NULL)
  1494. #else
  1495.     if ((f = fopen(ringfile,"rb")) == NULL)
  1496. #endif
  1497.     {    fprintf(pgpout,PSTR("\n\007Can't open key ring file '%s'\n"),ringfile);
  1498.         return(-1);
  1499.     }
  1500.     fseek (f, fp+packetlength, SEEK_SET);
  1501.     userids = 0;
  1502.     do     /* count user ID's, position nfp at next key */
  1503.     {    nfp = ftell(f);
  1504.         status = nextkeypacket(f, &ctb);
  1505.         if (status == 0 && ctb == CTB_USERID)
  1506.             ++userids;
  1507.     } while (status == 0 && !is_key_ctb(ctb));
  1508.     if (status < -1)
  1509.     {    fclose(f);
  1510.         return(-1);
  1511.     }
  1512.  
  1513.     if (keyID==NULL)    /* Human confirmation is required. */
  1514.     {    /* Supposedly the key was fully displayed by getpublickey */
  1515.         if (userids > 1)
  1516.         {    fprintf(pgpout, PSTR("\nKey has more than one user ID.\n\
  1517. Do you want to remove the whole key (y/N)? "));
  1518.             if (!getyesno('n'))
  1519.             {    /* find out which userid should be removed */
  1520.                 fseek (f, fp+packetlength, SEEK_SET);
  1521.                 for ( ; ; )
  1522.                 {    fp = ftell(f);
  1523.                     status = readkpacket(f, &ctb, (char *) userid, NULL, NULL);
  1524.                     if (status < 0 || is_key_ctb(ctb))
  1525.                     {    fclose(f);
  1526.                         fprintf(pgpout, PSTR("\nNo more user ID's\n"));
  1527.                         return(-1);
  1528.                     }
  1529.                     if (ctb == CTB_USERID)
  1530.                     {    fprintf(pgpout, PSTR("Remove \"%s\" (y/N)? "), userid);
  1531.                         if (getyesno('n'))
  1532.                             break;
  1533.                     }
  1534.                 }
  1535.                 do     /* also remove signatures and trust bytes */
  1536.                 {    nfp = ftell(f);
  1537.                     status = nextkeypacket(f, &ctb);
  1538.                 } while (status == 0  && !is_key_ctb(ctb) && ctb != CTB_USERID);
  1539.                 if (status < -1)
  1540.                 {    fclose(f);
  1541.                     return(-1);
  1542.                 }
  1543.             }
  1544.             rmuserid = TRUE;
  1545.         }
  1546.         else    /* only one user ID */
  1547.         {    fprintf(pgpout,
  1548.                 PSTR("\nAre you sure you want this key removed (y/N)? "));
  1549.             if (!getyesno('n'))
  1550.             {    fclose(f);
  1551.                 return(-1);    /* user said "no" */
  1552.             }
  1553.         }
  1554.     }
  1555.     fclose(f);
  1556.     packetlength = nfp - fp;
  1557.  
  1558.     /* open file f for read, in binary (not text) mode...*/
  1559. #ifdef VMS
  1560.     if ((f = fopen(ringfile,"rb","ctx=stm")) == NULL)
  1561. #else
  1562.     if ((f = fopen(ringfile,"rb")) == NULL)
  1563. #endif
  1564.     {    fprintf(pgpout,PSTR("\n\007Can't open key ring file '%s'\n"),ringfile);
  1565.         return(-1);
  1566.     }
  1567.  
  1568.     remove(SCRATCH_KEYRING_PATH);
  1569.     /* open file g for writing, in binary (not text) mode...*/
  1570.     if ((g = fopen(SCRATCH_KEYRING_PATH,"wb")) == NULL)
  1571.     {    fclose(f);
  1572.         return(-1);
  1573.     }
  1574.     copyfilepos(f,g,fp,0L);    /* copy file f to g up to position fp */
  1575.     copyfilepos(f,g,-1L,fp+packetlength); /* copy rest of file f */
  1576.     fclose(g);    /* close scratch file */
  1577.     fclose(f);    /* close key file */
  1578.     backup_rename(SCRATCH_KEYRING_PATH,ringfile);
  1579.     if (rmuserid)
  1580.         fprintf(pgpout,PSTR("\nUser ID removed from key ring.\n"));
  1581.     else
  1582.         fprintf(pgpout,PSTR("\nKey removed from key ring.\n"));
  1583.  
  1584.     return(0);    /* normal return */
  1585.  
  1586. }    /* remove_from_keyring */
  1587.  
  1588.  
  1589. int extract_from_keyring (char *mcguffin, char *keyfile, char *ringfile,
  1590.                 boolean transflag)
  1591. /*    Copy the first entry in key ring that has mcguffin string in
  1592.     userid and put it into keyfile.
  1593.     mcguffin is a null-terminated C string.
  1594. */
  1595. {
  1596.     FILE *f;
  1597.     FILE *g;
  1598.     long fp, dummy_fp;
  1599.     int packetlength=0, dummy_packetlength;
  1600.     byte ctb;
  1601.     int status;
  1602.     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
  1603.     byte keyID[KEYFRAGSIZE];
  1604.     byte userid[256];    /* key certificate userid */
  1605.     char fname[MAX_PATH], transfile[MAX_PATH], transname[MAX_PATH];
  1606.     word32 tstamp; byte *timestamp = (byte *) &tstamp; /* key cert tstamp */
  1607.     boolean append = FALSE;
  1608.     boolean whole_ring = FALSE;
  1609.  
  1610.     default_extension(ringfile, PGP_EXTENSION);
  1611.  
  1612.     if (!mcguffin  ||  strlen(mcguffin)==0 || strcmp(mcguffin, "*") == 0)
  1613.         whole_ring = TRUE;
  1614.  
  1615.     /* open file f for read, in binary (not text) mode...*/
  1616. #ifdef VMS
  1617.     if ((f = fopen(ringfile,"rb","ctx=stm")) == NULL)
  1618. #else
  1619.     if ((f = fopen(ringfile,"rb")) == NULL)
  1620. #endif
  1621.     {    fprintf(pgpout,PSTR("\n\007Can't open key ring file '%s'\n"),ringfile);
  1622.         return(-1);
  1623.     }
  1624.  
  1625.     if (!whole_ring)
  1626.     {
  1627.         strcpy((char *)userid, mcguffin);
  1628.         fprintf(pgpout,PSTR("\nExtracting from key ring: '%s'"),ringfile);
  1629.         fprintf(pgpout,PSTR(", userid \"%s\".\n"),EXTERNAL(mcguffin));
  1630.  
  1631.         status = getpublickey(TRUE, TRUE, ringfile, &fp, &packetlength, NULL,
  1632.                     timestamp, userid, n, e);
  1633.         if (status < 0)
  1634.         {    fprintf(pgpout,PSTR("\n\007Key not found in key ring '%s'.\n"),
  1635.                                     ringfile);
  1636.             fclose(f);
  1637.             return(0);    /* normal return */
  1638.         }
  1639.         extract_keyID(keyID, n);
  1640.     }
  1641.     else
  1642.     {
  1643.         do    /* set fp to first key packet */
  1644.             fp = ftell(f);
  1645.         while ((status = nextkeypacket(f, &ctb)) >= 0 && !is_key_ctb(ctb));
  1646.         if (status < 0)
  1647.         {    fclose(f);
  1648.             return(-1);
  1649.         }
  1650.         packetlength = ftell(f) - fp;
  1651.     }
  1652.  
  1653.     if (!keyfile  ||  strlen(keyfile)==0)
  1654.     {    fprintf(pgpout, PSTR("\nExtract the above key into which file? "));
  1655.         getstring( fname, sizeof(fname)-4, TRUE );
  1656.     }
  1657.     else
  1658.         strcpy(fname,keyfile);
  1659.     default_extension(fname,PGP_EXTENSION);
  1660.  
  1661.     /* If transport armoring, use a dummy file for keyfile */
  1662.     if (transflag)
  1663.     {    strcpy(transname, fname);
  1664.         strcpy(transfile, fname);
  1665.         force_extension(transfile, ASC_EXTENSION);
  1666.         strcpy (fname, SCRATCH_KEYRING_FILENAME);
  1667.     }
  1668.     if (file_exists( transflag?transfile:fname ))
  1669.     {
  1670.         if (!transflag && !whole_ring)
  1671.         {    /* see if the key is already present in fname */
  1672.             status = getpublickey(TRUE, FALSE, fname, &dummy_fp, &dummy_packetlength,
  1673.                     keyID, timestamp, userid, n, e);
  1674.             if (status >= 0)
  1675.             {    fclose(f);
  1676.                 fprintf(pgpout,PSTR("Key ID %s is already included in key ring '%s'.\n"),
  1677.                     keyIDstring(keyID), fname);
  1678.                 return(-1);
  1679.             }
  1680.         }
  1681.         if (whole_ring || transflag || status < -1)
  1682.         { /* if status < -1 then fname is not a keyfile, ask if it should be overwritten */
  1683.             fprintf(pgpout,PSTR("\n\007Output file '%s' already exists.  Overwrite (y/N)? "),
  1684.                 fname);
  1685.             if (!getyesno( 'n' ))
  1686.             {    fclose(f);
  1687.                 return(-1);    /* user chose to abort */
  1688.             }
  1689.         }
  1690.         else
  1691.             append = TRUE;
  1692.     }
  1693.  
  1694.     if ((g = fopen(fname,(append ? "r+b" : "wb"))) == NULL)
  1695.     {    if (append)
  1696.             fprintf(pgpout,PSTR("\n\007Can't open key ring file '%s'\n"),ringfile);
  1697.         else
  1698.             fprintf(pgpout,PSTR("\n\007Unable to create key file '%s'.\n"), fname);
  1699.         fclose(f);
  1700.         return(-1);
  1701.     }
  1702.     if (append)
  1703.         fseek(g, 0L, SEEK_END);
  1704.     do
  1705.     {
  1706.         copyfilepos(f, g, packetlength, fp);    /* Copy key out */
  1707.         /* Copy any following signature or userid packets */
  1708.         for ( ; ; )
  1709.         {    fp = ftell(f);
  1710.             status = nextkeypacket(f, &ctb);
  1711.             packetlength = ftell(f) - fp;
  1712.             if (status < 0  ||  is_key_ctb(ctb))
  1713.                 break;
  1714.             if (ctb==CTB_USERID  ||  is_ctb_type(ctb,CTB_SKE_TYPE))
  1715.                 copyfilepos(f, g, packetlength, fp);
  1716.         }
  1717.     }
  1718.     while (whole_ring && status >= 0);
  1719.  
  1720.     fclose(f);
  1721.     fclose(g);
  1722.  
  1723.     if (transflag)
  1724.     {    armor_file (fname, transfile, transname);
  1725.         wipefile (fname);
  1726.         remove (fname);
  1727.     }
  1728.  
  1729.     fprintf (pgpout,PSTR("\nKey extracted to file '%s'.\n"), transflag?transfile:fname);
  1730.  
  1731.     return (0);    /* normal return */
  1732. }    /* extract_from_keyring */
  1733.  
  1734.  
  1735. /*======================================================================*/
  1736.  
  1737. int merge_key_to_ringfile(char *keyfile, char* ringfile, long fp,
  1738.                 int packetlength)
  1739. /* Copy the key data in keyfile into ringfile, replacing the data that
  1740.    is in ringfile starting at fp and for length packetlength.
  1741. */
  1742. {    FILE    *f, *g, *h;
  1743.  
  1744.     if (build_path(SCRATCH_KEYRING_PATH,SCRATCH_KEYRING_FILENAME,ringfile)<0)
  1745.         return(-1);        /* File path too long */
  1746.     remove(SCRATCH_KEYRING_PATH);
  1747.     /* open file f for reading, binary, as keyring file */
  1748. #ifdef VMS
  1749.     if ((f = fopen(ringfile,"rb","ctx=stm")) == NULL)
  1750. #else
  1751.     if ((f = fopen(ringfile,"rb")) == NULL)
  1752. #endif
  1753.         return(-1);
  1754.     /* open file g for writing, binary, as scratch keyring file */
  1755.     if ((g = fopen(SCRATCH_KEYRING_PATH,"wb")) == NULL)
  1756.     {    fclose(f);
  1757.         return(-1);
  1758.     }
  1759.     /* open file h for reading, binary, as key file to be inserted */
  1760. #ifdef VMS
  1761.     if ((h = fopen(keyfile,"rb","ctx=stm")) == NULL)
  1762. #else
  1763.     if ((h = fopen(keyfile,"rb")) == NULL)
  1764. #endif
  1765.     {    fclose(f);
  1766.         fclose(g);
  1767.         return(-1);
  1768.     }
  1769.     /* Copy pre-key keyring data from f to g */
  1770.     copyfile(f,g,fp);
  1771.     /* Copy temp key data from h to g */
  1772.     copyfile(h,g,-1L);
  1773.     /* Copy post-key keyring data from f to g */
  1774.     copyfilepos(f,g,-1L,fp+packetlength);
  1775.     fclose(f);
  1776.     fclose(g);
  1777.     fclose(h);
  1778.  
  1779.     backup_rename(SCRATCH_KEYRING_PATH,ringfile);
  1780.  
  1781.     return(0);    /* normal return */
  1782. }    /* merge_key_to_ringfile */
  1783.  
  1784. static int insert_userid(char *keyfile, byte *userid, long fpos)
  1785. {    /* insert userid and trust byte at position fpos in file keyfile */
  1786.     char *tmpf;
  1787.     FILE *f, *g;
  1788.  
  1789.     tmpf = tempfile(TMP_TMPDIR);
  1790.     if ((f = fopenbin(keyfile, "r")) == NULL)
  1791.         return(-1);
  1792.     if ((g = fopenbin(tmpf, "w")) == NULL)
  1793.     {    fclose(f);
  1794.         return(-1);
  1795.     }
  1796.     copyfile(f, g, fpos);
  1797.     putc(CTB_USERID, g);
  1798.     fwrite(userid, 1, userid[0]+1, g);
  1799.     write_trust(g, KC_LEGIT_COMPLETE);
  1800.     copyfile(f, g, -1L);
  1801.     fclose(f);
  1802.     fflush(g);
  1803.     if (ferror(g))
  1804.     {    fclose(g);
  1805.         return(-1);
  1806.     }
  1807.     fclose(g);
  1808.     return(savetempbak(tmpf, keyfile));
  1809. }
  1810.  
  1811. int dokeyedit(char *mcguffin, char *ringfile)
  1812. /*    Edit the userid and/or pass phrase for an RSA key pair, and
  1813.     put them back into the ring files.
  1814. */
  1815. {    unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION], d[MAX_UNIT_PRECISION],
  1816.          p[MAX_UNIT_PRECISION], q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION];
  1817.     char *fname, secring[MAX_PATH];
  1818.     FILE *f;
  1819.     word16 iv[4]; /* for IDEA CFB mode, to protect RSA secret key */
  1820.     byte userid[256];
  1821.     byte userid1[256];
  1822.     char passphrase[256];
  1823.     word32 tstamp; byte *timestamp = (byte *) &tstamp;    /* key certificate timestamp */
  1824.     byte keyID[KEYFRAGSIZE];
  1825.     boolean hidekey;    /* TRUE iff secret key is encrypted */
  1826.     boolean changed=FALSE, changeID=FALSE;
  1827.     byte ctb;
  1828.     int status;
  1829.     long fpp,fps,trust_pos;
  1830.     int pplength=0, pslength=0;
  1831.     byte ideakey[16];
  1832.     byte keyctrl;
  1833.  
  1834.     if (!ringfile || strlen(ringfile)==0 || !mcguffin || strlen(mcguffin)==0)
  1835.         return(-1);    /* Need ringfile name, user name */
  1836.  
  1837.     force_extension(ringfile,PGP_EXTENSION);
  1838.  
  1839.     strcpy((char *)userid, mcguffin);
  1840.     fprintf(pgpout,PSTR("\nEditing userid \"%s\" in key ring: '%s'.\n"),
  1841.         EXTERNAL((char *)userid),ringfile);
  1842.  
  1843.     if (!file_exists (ringfile))
  1844.     {    fprintf(pgpout,PSTR("\nCan't open public key ring file '%s'\n"),
  1845.             ringfile);
  1846.         return(-1);
  1847.     }
  1848.  
  1849.     status = getpublickey(TRUE, TRUE, ringfile, &fpp, &pplength, NULL,
  1850.                 timestamp, userid, n, e);
  1851.     if (status < 0)
  1852.     {    fprintf(pgpout,PSTR("\n\007Key not found in key ring '%s'.\n"),
  1853.             ringfile);
  1854.         return(-1);
  1855.     }
  1856.  
  1857.     /* Now add to pplength any following key control certificate */
  1858. #ifdef VMS
  1859.     if ((f = fopen(ringfile,"r+b","ctx=stm")) == NULL)
  1860. #else
  1861.     if ((f = fopen(ringfile,"r+b")) == NULL)
  1862. #endif
  1863.     {    fprintf(pgpout,PSTR("\n\007Can't open key ring file '%s'\n"),ringfile);
  1864.         return(-1);
  1865.     }
  1866.  
  1867.     fseek(f, fpp, SEEK_SET);
  1868.     if (is_compromised(f))
  1869.     {    fprintf(pgpout, PSTR("\n\007This key has been revoked by its owner.\n"));
  1870.         fclose(f);
  1871.         return(-1);
  1872.     }
  1873.     trust_pos = fpp+pplength;
  1874.     fseek(f, trust_pos, SEEK_SET);
  1875.     if (read_trust(f, &keyctrl) < 0)
  1876.         trust_pos = -1;        /* keyfile: no trust byte */
  1877.  
  1878.     extract_keyID(keyID, n);
  1879.  
  1880.     /* Now read private key, too */
  1881.     strcpy(secring, ringfile);
  1882.     strcpy(file_tail(secring), SECRET_KEYRING_FILENAME);
  1883.  
  1884.     if (!file_exists (secring))
  1885.     {    fprintf(pgpout,PSTR("\nCan't open secret key ring file '%s'\n"),
  1886.             secring);
  1887.         fclose(f);
  1888.         return(-1);
  1889.     }
  1890.  
  1891.     /* Get position of key in secret key file */
  1892.     strcpy((char *)userid1, mcguffin);
  1893.     (void)getpublickey(TRUE, FALSE, secring, &fps, &pslength, NULL,
  1894.         timestamp, userid1, n, e);
  1895.     /* This was done to get us fps and pslength */
  1896.     strcpy((char *)userid1, mcguffin);
  1897.     status = getsecretkey(TRUE, FALSE, secring, keyID, timestamp,
  1898.         passphrase, &hidekey, userid1, n, e, d, p, q, u);
  1899.  
  1900.     if (status < 0)        /* key not in secret keyring: edit owner trust */
  1901.     {    int i;
  1902.  
  1903.         fprintf(pgpout, PSTR("\nNo secret key available.  Editing public key trust parameter.\n"));
  1904.         if (trust_pos < 0)
  1905.         {    fprintf(pgpout,PSTR("\n\007File '%s' is not a public keyring.\n"), ringfile);
  1906.             fclose(f);
  1907.             return(-1);
  1908.         }
  1909.         show_key(f, fpp, SHOW_ALL);
  1910.  
  1911.         init_trust_lst();
  1912.         fprintf(pgpout, PSTR("Current trust for this key's owner is: %s\n"),
  1913.                 trust_lst[keyctrl & KC_OWNERTRUST_MASK]);
  1914.  
  1915.         PascalToC((char *)userid);    /* convert to C string for display */
  1916.         i = ask_owntrust((char *) userid, keyctrl);
  1917.         if (i == (keyctrl & KC_OWNERTRUST_MASK))
  1918.         {    fclose(f);
  1919.             return(0);    /* unchanged */
  1920.         }
  1921.  
  1922.         if (i < 0 || i > KC_OWNERTRUST_ALWAYS)
  1923.         {
  1924.             fclose(f);
  1925.             return(-1);
  1926.         }
  1927.         keyctrl = (keyctrl & ~KC_OWNERTRUST_MASK) | i;
  1928.  
  1929.         fseek(f, trust_pos, SEEK_SET);
  1930.         write_trust(f, keyctrl);
  1931.         fclose(f);
  1932.         fprintf (pgpout, PSTR("Public key ring updated.\n"));
  1933.         return(0);
  1934.     }
  1935.     if (trust_pos > 0 && (keyctrl & (KC_BUCKSTOP|KC_OWNERTRUST_MASK)) !=
  1936.             (KC_OWNERTRUST_ULTIMATE|KC_BUCKSTOP))
  1937.     {    /* key is in secret keyring but buckstop is not set */
  1938.         fprintf(pgpout, PSTR("\nUse this key as an ultimately-trusted introducer (y/N)? "), userid);
  1939.         if (getyesno('n'))
  1940.         {    fseek(f, trust_pos, SEEK_SET);
  1941.             keyctrl = KC_OWNERTRUST_ULTIMATE|KC_BUCKSTOP;
  1942.             write_trust(f, keyctrl);
  1943.         }
  1944.     }
  1945.  
  1946.     /* Show user her ID again to be clear */
  1947.     PascalToC((char *)userid);
  1948.     fprintf(pgpout,PSTR("\nCurrent user ID: %s"),EXTERNAL((char *)userid));
  1949.     CToPascal((char *)userid);
  1950.  
  1951.     fprintf(pgpout, PSTR("\nDo you want to change your user ID (y/N)? "));
  1952.     if (getyesno('n'))    /* user said yes */
  1953.     {    fprintf(pgpout,PSTR("\nEnter the new user ID: "));
  1954.         getstring((char *)userid,255,TRUE); /* echo keyboard input */
  1955.         if (userid[0] == '\0')
  1956.         {    fclose(f);
  1957.             return(-1);
  1958.         }
  1959.         INTERNAL((char *)userid);
  1960.         fprintf(pgpout, PSTR("\nMake this user ID the primary user ID for this key (y/N)? "));
  1961.         if (!getyesno('n'))
  1962.         {    /* possition file pointer at selected user id */
  1963.             int pktlen;
  1964.             long fpuser;
  1965.  
  1966.             strcpy((char *)userid1, mcguffin);
  1967.             if (getpubuserid(ringfile, fpp, userid1, &fpuser, &pktlen) < 0)
  1968.             {    fclose(f);
  1969.                 return(-1);
  1970.             }
  1971.             fseek(f, fpuser, SEEK_SET);
  1972.         }
  1973.         else    /* possition file pointer at key packet */
  1974.             fseek(f, fpp, SEEK_SET);
  1975.         nextkeypacket(f, &ctb);    /* skip userid or key packet */
  1976.         do    /* new user id will be inserted before next userid or key packet */
  1977.         {    fpp = ftell(f);
  1978.             if (nextkeypacket(f, &ctb) < 0)
  1979.                 break;
  1980.         } while (ctb != CTB_USERID && !is_key_ctb(ctb));
  1981.         CToPascal((char *)userid);        /* convert to length-prefixed string */
  1982.         changeID = TRUE;
  1983.         changed = TRUE;
  1984.     }
  1985.     fclose(f);
  1986.  
  1987.     fprintf (pgpout,PSTR("\nDo you want to change your pass phrase (y/N)? "));
  1988.     if (getyesno('n'))    /* user said yes */
  1989.     {    hidekey = (getideakey(passphrase, (char *) ideakey, 2) > 0);
  1990.         changed = TRUE;
  1991.     }
  1992.     else
  1993.     {    if (hidekey)
  1994.             hashpass( passphrase, strlen(passphrase), ideakey );
  1995.     }
  1996.  
  1997.     if (!changed)
  1998.     {    fprintf (pgpout, PSTR("(No changes will be made.)\n"));
  1999.         if (hidekey)
  2000.             burn((byteptr)passphrase);
  2001.         goto done;
  2002.     }
  2003.  
  2004.     /* init CFB IDEA key */
  2005.     if (hidekey)
  2006.     {    fill0(iv,8);
  2007.         initcfb_idea(iv,ideakey,FALSE);
  2008.         burn((byteptr)passphrase);    /* burn sensitive data on stack */
  2009.     }
  2010.  
  2011.     /* First write secret key data to a file */
  2012.     fname = tempfile(TMP_TMPDIR|TMP_WIPE);
  2013.     writekeyfile(fname,hidekey,timestamp,userid,n,e,d,p,q,u);
  2014.     if (merge_key_to_ringfile(fname,secring,fps,pslength) < 0)
  2015.     {    fprintf (pgpout, PSTR("\n\007Unable to update secret key ring.\n"));
  2016.         goto err;
  2017.     }
  2018.     fprintf (pgpout, PSTR("\nSecret key ring updated...\n"));
  2019.  
  2020.     /* Now write public key data to file */
  2021.     if (changeID)
  2022.     {
  2023.         if (insert_userid(ringfile, userid, fpp) < 0)
  2024.         {    fprintf (pgpout, PSTR("\n\007Unable to update public key ring.\n"));
  2025.             goto err;
  2026.         }
  2027.         fprintf (pgpout, PSTR("Public key ring updated.\n"));
  2028.     }
  2029.     else
  2030.         fprintf (pgpout, PSTR("(No need to update public key ring)\n"));
  2031.  
  2032.     if (hidekey)    /* done with IDEA to protect RSA secret key */
  2033.         close_idea();
  2034.  
  2035.     rmtemp(fname);
  2036.  
  2037. done:
  2038.     mp_burn(d);    /* burn sensitive data on stack    */
  2039.     mp_burn(p);    /*     "        "        "    "    "    */
  2040.     mp_burn(q);    /*    "        "        "    "    "    */
  2041.     mp_burn(u);    /*    "        "        "    "    "    */
  2042.     mp_burn(e);    /*    "        "        "    "    "    */
  2043.     mp_burn(n);    /*    "        "        "    "    "    */
  2044.     burn(iv);    /*    "        "        "    "    "    */
  2045.  
  2046.     return(0);    /* normal return */
  2047. err:
  2048.     mp_burn(d);    /* burn sensitive data on stack */
  2049.     mp_burn(p);    /*    "        "        "    "    "    */
  2050.     mp_burn(q);    /*    "        "        "    "    "    */
  2051.     mp_burn(u);    /*    "        "        "    "    "    */
  2052.     mp_burn(e);    /*    "        "        "    "    "    */
  2053.     mp_burn(n);    /*    "        "        "    "    "    */
  2054.     burn(iv);    /*    "        "        "    "    "    */
  2055.  
  2056.     rmtemp(fname);
  2057.  
  2058.     return(-1);    /* error return */
  2059.  
  2060. }    /* dokeyedit */
  2061.  
  2062.  
  2063. /*======================================================================*/
  2064.  
  2065.  
  2066.  
  2067. int dokeygen(char *numstr, char *numstr2)
  2068. /*    Do an RSA key pair generation, and write them out to the keyring files.
  2069.     numstr is a decimal string, the desired bitcount for the modulus n.
  2070.     numstr2 is a decimal string, the desired bitcount for the exponent e.
  2071. */
  2072. {    unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION], d[MAX_UNIT_PRECISION],
  2073.          p[MAX_UNIT_PRECISION], q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION];
  2074.     char *fname;
  2075.     char ringfile[MAX_PATH];
  2076.     word16 iv[4]; /* for IDEA CFB mode, to protect RSA secret key */
  2077.     byte userid[256];
  2078.     short keybits,ebits;
  2079.     word32 tstamp; byte *timestamp = (byte *) &tstamp;        /* key certificate timestamp */
  2080.     boolean hidekey;    /* TRUE iff secret key is encrypted */
  2081.     byte ideakey[16];
  2082.  
  2083.     if (!numstr || strlen(numstr)==0)
  2084.     {    fprintf(pgpout,PSTR("\nPick your RSA key size:\
  2085. \n    1)     384 bits- Casual grade, fast but less secure\
  2086. \n    2)     512 bits- Commercial grade, medium speed, good security\
  2087. \n    3)    1024 bits- Military grade, very slow, highest security\
  2088. \nChoose 1, 2, or 3, or enter desired number of bits: "));
  2089.         numstr = (char *)userid;    /* use userid buffer as scratchpad */
  2090.         getstring(numstr,5,TRUE);    /* echo keyboard */
  2091.     }
  2092.  
  2093.     keybits = 0;
  2094.     while ((*numstr>='0') && (*numstr<='9'))
  2095.         keybits = keybits*10 + (*numstr++ - '0');
  2096.  
  2097.     if (keybits==0)    /* user entered null response */
  2098.         return(-1);    /* error return */
  2099.  
  2100.     /* Standard default key sizes: */
  2101.     if (keybits==1) keybits=384;    /* Casual grade */
  2102.     if (keybits==2) keybits=512;    /* Commercial grade */
  2103.     if (keybits==3) keybits=1024;    /* Military grade */
  2104.  
  2105. #ifndef DEBUG
  2106.     /* minimum RSA keysize: */
  2107.     if (keybits<384) keybits=384;
  2108. #endif
  2109.  
  2110. #ifdef MERRITT    
  2111. /*    If we use Merritt's modmult algorithm, the primes p and q's 
  2112.     bit length should not be an exact multiple of UNITSIZE, 
  2113.     because Merritt's modmult algorithm performs slowest in that 
  2114.     case, wasting an extra unit of precision for overflow.
  2115. */
  2116.     if ((keybits % (2*UNITSIZE))==0)
  2117.         keybits -= 2;    /* make each prime one bit shorter. */
  2118. #endif    /* MERRITT */
  2119.  
  2120.     ebits = 0;    /* number of bits in e */
  2121.     while ((*numstr2>='0') && (*numstr2<='9')) 
  2122.         ebits = ebits*10 + (*numstr2++ - '0');
  2123.  
  2124.     fprintf(pgpout,PSTR("\nGenerating an RSA key with a %d-bit modulus... "),keybits);
  2125.  
  2126.     fprintf(pgpout,
  2127. PSTR("\nYou need a user ID for your public key.  The desired form for this\n\
  2128. user ID is your name, followed by your E-mail address enclosed in\n\
  2129. <angle brackets>, if you have an E-mail address.\n\
  2130. For example:  John Q. Smith <12345.6789@compuserve.com>\n"));
  2131.     fprintf(pgpout,PSTR("\nEnter a user ID for your public key: \n"));
  2132.     getstring((char *)userid,255,TRUE);    /* echo keyboard input */
  2133.     if (userid[0]=='\0')    /* user entered null response */
  2134.         return(-1);    /* error return */
  2135.     INTERNAL((char *)userid);
  2136.     CToPascal((char *)userid);    /* convert to length-prefixed string */
  2137.  
  2138.     {    char passphrase[256];
  2139.         fprintf(pgpout,
  2140. PSTR("\nYou need a pass phrase to protect your RSA secret key.\n\
  2141. Your pass phrase can be any sentence or phrase and may have many\n\
  2142. words, spaces, punctuation, or any other printable characters. "));
  2143.         hidekey = (getideakey(passphrase, (char *) ideakey, 2) > 0);
  2144.         /* init CFB IDEA key */
  2145.         if (hidekey)
  2146.         {    fill0(iv,8);
  2147.             initcfb_idea(iv,ideakey,FALSE);
  2148.             burn((byteptr)passphrase);    /* burn sensitive data on stack */
  2149.         }
  2150.     }
  2151.  
  2152.     fprintf(pgpout,PSTR("\nNote that key generation is a VERY lengthy process.\n"));
  2153.  
  2154.     if (rsa_keygen(n,e,d,p,q,u,keybits,ebits) < 0)
  2155.     {    fprintf(pgpout,PSTR("\n\007Keygen failed!\n"));
  2156.         return(-1);    /* error return */
  2157.     }
  2158.  
  2159.     if (verbose)
  2160.     {
  2161.         fprintf(pgpout,PSTR("Key ID %s\n"), key2IDstring(n));
  2162.  
  2163.         mp_display(" modulus n = ",n);
  2164.         mp_display("exponent e = ",e);
  2165.  
  2166.         mp_display("exponent d = ",d);
  2167.         mp_display("   prime p = ",p);
  2168.         mp_display("   prime q = ",q);
  2169.         mp_display(" inverse u = ",u);
  2170.     }
  2171.  
  2172.     get_timestamp(timestamp);    /* Timestamp when key was generated */
  2173.  
  2174.     fputc('\007',pgpout);  /* sound the bell when done with lengthy process */
  2175.     fputc('\n',pgpout);
  2176.  
  2177.     /* First, write out the secret key... */
  2178.     fname = tempfile(TMP_TMPDIR|TMP_WIPE);
  2179.     writekeyfile(fname,hidekey,timestamp,userid,n,e,d,p,q,u); 
  2180.     buildfilename(ringfile,SECRET_KEYRING_FILENAME);
  2181.     if (file_exists(ringfile))
  2182.     {    merge_key_to_ringfile(fname,ringfile,0L,0);
  2183.         rmtemp(fname);
  2184.     }
  2185.     else
  2186.         savetemp(fname, ringfile);
  2187.  
  2188.     /* Second, write out the public key... */
  2189.     fname = tempfile(TMP_TMPDIR|TMP_WIPE);
  2190.     writekeyfile(fname,FALSE,timestamp,userid,n,e,NULL,NULL,NULL,NULL);
  2191.     buildfilename(ringfile,PUBLIC_KEYRING_FILENAME);
  2192.     if (file_exists(ringfile))
  2193.     {    merge_key_to_ringfile(fname,ringfile,0L,0);
  2194.         rmtemp(fname);
  2195.     }
  2196.     else
  2197.         savetemp(fname, ringfile);
  2198.     
  2199.     if (hidekey)    /* done with IDEA to protect RSA secret key */
  2200.         close_idea();
  2201.  
  2202.     mp_burn(d);    /* burn sensitive data on stack */
  2203.     mp_burn(p);    /* burn sensitive data on stack */
  2204.     mp_burn(q);    /* burn sensitive data on stack */
  2205.     mp_burn(u);    /* burn sensitive data on stack */
  2206.     mp_burn(e);    /* burn sensitive data on stack */
  2207.     mp_burn(n);    /* burn sensitive data on stack */
  2208.     burn(iv);    /* burn sensitive data on stack */
  2209.  
  2210.     fprintf(pgpout,PSTR("\007Key generation completed.\n"));
  2211.  
  2212.     /*    Force initialization of cryptographically strong pseudorandom
  2213.         number generator seed file for later use...
  2214.     */
  2215.     strong_pseudorandom((byte *) iv,1);
  2216.  
  2217.     return(0);    /* normal return */
  2218. }    /* dokeygen */
  2219.  
  2220.